线程与进程
一个进程就是一个可执行文件。在VS系统中,一个工程通过编译,链接一些库之后就会变成一个可执行文件,所以在VS2015中,一个工程就可以看为一个进程。在一个进程中可以有多个线程的存在,所谓线程就是可以同时运作的代码块。在这些线程中有一个主线程和很多的子线程。
thread库和join、joinable函数
thread可以创建一个子线程,格式如下
1 | thread a(funname); |
这样就可以创建一个a的子线程,可以调用a.join()强制让主线程等待子线程运行。
在默认情况下主线程和子线程是共同运行的,例如运行如下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 void f()
{
cout << "犯得上反对1" << endl;
cout << "犯得上反对2" << endl;
cout << "犯得上反对3" << endl;
cout << "犯得上反对4" << endl;
cout << "犯得上反对5" << endl;
cout << "犯得上反对6" << endl;
cout << "犯得上反对7" << endl;
cout << "犯得上反对8" << endl;
cout << "犯得上反对9" << endl;
cout << "犯得上反对10" << endl;
cout << "犯得上反对11" << endl;
cout << "犯得上反对12" << endl;
cout << "犯得上反对13" << endl;
cout << "犯得上反对14" << endl;
cout << "犯得上反对15" << endl;
cout << "犯得上反对16" << endl;
cout << "犯得上反对1" << endl;
cout << "犯得上反对2" << endl;
cout << "犯得上反对3" << endl;
cout << "犯得上反对4" << endl;
cout << "犯得上反对5" << endl;
cout << "犯得上反对6" << endl;
cout << "犯得上反对7" << endl;
cout << "犯得上反对8" << endl;
cout << "犯得上反对9" << endl;
cout << "犯得上反对10" << endl;
cout << "犯得上反对11" << endl;
cout << "犯得上反对12" << endl;
cout << "犯得上反对13" << endl;
cout << "犯得上反对14" << endl;
cout << "犯得上反对15" << endl;
cout << "犯得上反对16" << endl;
}
int main()
{
thread obj(f);
obj.detach();
//obj.join();
cout << "dsadass1" << endl;
cout << "dsadass2" << endl;
cout << "dsadass3" << endl;
cout << "dsadass4" << endl;
cout << "dsadass5" << endl;
cout << "dsadass6" << endl;
cout << "dsadass7" << endl;
cout << "dsadass8" << endl;
system("pause");
return 0;
}会出现以下的结果
如果采用detach方法则主子线程会共同运行、互不影响
如果f有多个参数例如下面这样
1
2
3
4
5
6 void myprint(const int & i, char*pmy)
{
cout << i << endl;
cout << pmy << endl;
return;
} 则在构建thread的obj的时候需要加上实参,这个时候的第一个参数实际上不是引用传递,而是值传递。但是第二个按指针传递的是按引用传递、所以在主线程执行结束,实参被回收,则按指针传递的内容不安全
这种情况对于字符串采用下面这种方式
1 thrad obj(f,a,string(字符数组));
在类参数初始化多线程时避免使用隐式类型转换,应该在创建线程对象的时候就显示的创建临时对象,在函数参数里面用引用来接
这些问题的讨论在detach中存在的问题
joinable和detachable
一个进程在join后不能在detach、在detach会后不能再join,可以只用joinable查看石佛还能join.
使用类和对象事项多线程
在使用类来实现多线程时,此类必须重载operator(),应为只有这样才能是一个可调用的对象。声明格式如下
1 | class A |
注意:必须是类的对象去初始化thread
在thread obj(b)的过程中,首先thread将b拷贝到子线程中,此时会调用类的拷贝构造函数。所以如果主程序比子程序更快的执行完成(例如本例的结果),这样在程序结束后、在主程序声明的变量,会在主程序结束后,子程序也不会奔溃。这个设计是十分合理的。
这是本例的执行结果。
最后一个析构函数没有完成是因为,主程序在return 0的时候蔡释放内存,而VS2015在return0之后,程序执行窗口会关闭,所以最后的析构函数没打印
使用lambda表达式创建线程
在main函数中使用lambda表达式 ,c++lambda表达式如下
1 | auto lamthread = [] { |
lambda表达式同样可以使用join和detach
线程id
主线程和子线程对应一个不同数字,可以通过std::this_thread::get_id()来获取
传递类对象、智能指针作为线程参数