标准写法:

#include<iostream>
#include<thread>
using namespace std;
void MyThread()
{
cout << "MyThread线程1开始了" << endl;
cout << ".................." << endl;
cout << "MyThread线程1结束了" << endl;
} int main()
{
thread my(MyThread);
my.join(); cout<<"主线程开始了"<< endl;
cout<<"............."<< endl;
cout<<"主线程结束了"<< endl; return 0;
}

输出结果:

分析:

首先利用可调用对象MyThread创建了子线程my;

然后调用类thread的函数join,表示只有当我的子线程结束了,主线程才可以结束;说白了它的作用就是用来堵塞主线程的.

如果不加join函数,那么主进程和子进程就会同时执行,不分先后,如果子线程还没结束主线程就结束了,那么系统会抛出异常,如下代码:

#include<iostream>
#include<thread>
using namespace std;
void MyThread()
{
cout << "MyThread线程1开始了" << endl;
cout << ".................." << endl;
cout << "MyThread线程1结束了" << endl;
} int main()
{
thread my(MyThread);
//my.join(); cout<<"主线程开始了"<< endl;
cout<<"............."<< endl;
cout<<"主线程结束了"<< endl; return 0;
}

输出:

如果我就想让主线程先退出,但是不抛出异常,那么可以用detach(),如下代码:

#include<iostream>
#include<thread>
using namespace std;
void MyThread()
{
cout << "MyThread线程1开始了" << endl;
cout << ".................." << endl;
cout << "MyThread线程1结束了" << endl;
} int main()
{
thread my(MyThread);
my.detach(); cout<<"主线程开始了"<< endl;
cout<<"............."<< endl;
cout<<"主线程结束了"<< endl; return 0;
}

输出:

对于使用detach(),存在许多隐患,比如:

#include<iostream>
#include<thread>
using namespace std;
class MyThread
{
public:
int &x;
MyThread(int &_x):x(_x) {}
void operator()()
{ cout << "子线程开始执行了" << endl;
cout << "x的值是:" << x << endl;
cout << "..............." << endl;
cout << "子线程结束了" << endl;
}
}; int main()
{
int data = 1;
    MyThread myobj(data);
thread my(myobj);
my.detach(); cout<<"主线程开始了"<< endl;
cout<<"............."<< endl;
cout<<"主线程结束了"<< endl; return 0;
}

输出:

分析:

1.这里造成的原因主要就是因为我的类中含有引用,对于刚开始用int data=1生成的变量,main结束后(主线程结束),data就会消失,由于我使用了detach,所以主线程和子线程谁先谁后结束不确定,如果主线程先结束了,data也会跟着消失,子线程再去访问该数据便会无从寻起。

基于此,可能连带产生如下困惑,如下两行代码:

MyThread myobj(data);。。。。。。。。。。。。①
thread my(myobj); .。。。。。。。。。。。。。。②

如果主线程先结束,那么myobj对象一同消失,那么②的代码中的myobj不也会消失吗?

为了解答这个问题,做如下实验:

#include<iostream>
#include<thread>
using namespace std;
class MyThread
{
public:
int &x;
MyThread(int &_x):x(_x) {}
MyThread(const MyThread& another):x(another.x)
{ cout << "拷贝构造函数被执行" << endl;
}
~MyThread()
{
cout << "析构函数被执行" << endl;
}
void operator()()
{ cout << "子线程开始执行了" << endl;
cout << "x的值是:" << x << endl;
cout << "..............." << endl;
cout << "子线程结束了" << endl;
}
}; int main()
{
int data = 1;
MyThread myobj(data);
thread my(myobj);
my.detach(); cout<<"主线程开始了"<< endl;
cout<<"............."<< endl;
cout<<"主线程结束了"<< endl; return 0;
}

输出:

以上代码只有thread my(myobj); 这一句才有可能发生拷贝构造.

所以对于:

MyThread myobj(data);。。。。。。。。。。。。①
thread my(myobj); .。。。。。。。。。。。。。。②

①到②会发生拷贝构造,图的运行结果就是证明。

如果join或者detach其中一个已被使用,那么就不能再次被使用,

类库提供了一个joinable函数可以判断是否已被使用,看如下代码:

 1 #include<iostream>
2 #include<thread>
3 using namespace std;
4 class MyThread
5 {
6 public:
7 int &x;
8 MyThread(int &_x):x(_x) {}
9 MyThread(const MyThread& another):x(another.x)
10 {
11
12 cout << "拷贝构造函数被执行" << endl;
13 }
14 ~MyThread()
15 {
16 cout << "析构函数被执行" << endl;
17 }
18 void operator()()
19 {
20
21 cout << "子线程开始执行了" << endl;
22 cout << "x的值是:" << x << endl;
23 cout << "..............." << endl;
24 cout << "子线程结束了" << endl;
25 }
26 };
27
28 int main()
29 {
30 int data = 1;
31 MyThread myobj(data);
32 thread my(myobj);
33 my.join(); 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。①
34 if (my.joinable())
35 {
36 cout << "join或者detach可以被使用" << endl;
37 }
38 else
39 {
40 cout << "join或者detach已经被用" << endl;
41 }
42 my.detach();。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。②
43 if (my.joinable())
44 {
45 cout << "join或者detach可以被使用" << endl;
46 }
47 else
48 {
49 cout << "join或者detach已经被用" << endl;
50 }
51 cout<<"主线程开始了"<< endl;
52 cout << "..............." << endl;
53 cout << "主线程结束了" << endl;
54
55 return 0;
56 }

对①和②插入断点进行调试:

第一次进入了if语句,继续调试:

当执行第二个时候发生了异常。

继续实验:

更加证实了前面的观点,join或者detach两者只能使用其中的一个,并且只能一次。

最新文章

  1. 4.Android 打包时出现的Android Export aborted because fatal error were founds [closed]
  2. 第二篇 基于.net搭建热插拔式web框架(沙箱的构建)
  3. Activity系列讲解---Activity运行时的屏幕方向,全屏,窗体模式的设置
  4. render()方法是render_to_response
  5. 什么是OAuth授权?
  6. mima开发实列
  7. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【九】——API变了,客户端怎么办?
  8. Linux命令(1) - 查看内存使用情况: free -hm
  9. table点击一行显示下一行的特效
  10. Microsoft SQL Server 2008 安装图解(Windows 7)
  11. android脚步---图片浏览
  12. C# DataTable下载
  13. linux 常用指令
  14. bond-vlan-bridge
  15. 产品激活 比如Windows激活 , office激活 等激活的原理是什么? KMS等激活工具安全吗?
  16. docker学习实践之路[第一站]环境安装
  17. 风景区的面积及道路状况分析问题 test
  18. 你了解border-radius吗?
  19. c#的SortedList使用方法
  20. Spring----Spring Boot Rest的使用方法

热门文章

  1. windows10 下使用 spdlog 总结(spdlog 1.7)
  2. 【九度OJ】题目1018:统计同成绩学生人数 解题报告
  3. 【LeetCode】733. Flood Fill 解题报告(Python)
  4. 【LeetCode】611. Valid Triangle Number 解题报告(Python)
  5. 1131 - Just Two Functions
  6. What Makes for Good Views for Contrastive Learning
  7. Two pointer方法
  8. javaScript系列 [27]- DOM
  9. Java基础周测一、二(50题)
  10. 编写Java程序,实现从控制台输入对应个数的整数,输出对输入整数的从大到小显示