cpp11多线程2-join注意

join()函数的作用是让主线程的等待该子线程完成,然后主线程再继续执行。这种情况下,子线程可以安全的访问主线程中的资源。子线程结束后由主线程负责回收子线程资源。一个子线程只能调用join()和detach()中的一个,且只允许调用一次。可以调用joinable()来判断是否可以成功调用join()或detach()。

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
#include <thread>
#include <iostream>

using namespace std;

void test()
{
cout << "子线程开始执行!" << endl;
//do something
cout << "子线程执行完毕!" << endl;
}
int main()
{
cout << "主线程开始执行!" << endl;
thread t(test);
cout << "join()是否可调:" << boolalpha << t.joinable() << endl;
t.join(); //主线程等待子线程
cout << "join()是否可调:" << boolalpha << t.joinable() << endl;
cout << "主线程执行完毕!" << endl;
return 0;
}

结果输出:

主线程开始执行!
join()是否可调:true
子线程开始执行!
子线程执行完毕!
join()是否可调:false
主线程执行完毕!

注意

1、为了确保子线程程序在发送异常退出前完成,就需要对注意调用join()函数的位置,否则当主线发生异常而此时还没有调用到join()函数,那么子线程随主线程终止。解决方法是在异常处理中调用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
#include <thread>
#include <iostream>

using namespace std;

static void func()
{
cout << "子线程func开始执行!" << endl;
//do something
int i = 100000;
while (i--) {}
cout << "子线程func执行结束!" << endl;
}

int main()
{
cout << "主线程main开始执行!" << endl;
thread t(func);
throw 123;
t.join();
cout << "主线程main执行结束!" << endl;
return 0;
}

1.png

在异常处理中调用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
#include <thread>
#include <iostream>
#include <cstdlib> //for rand()

using namespace std;

void func()
{
cout << "子线程func开始执行!" << endl;
//do something
int i = 100000;
while(i--) { }
cout << "子线程func执行结束!" << endl;
}

int main()
{
cout << "主线程main开始执行!" << endl;
thread t(func);
try
{
//do something
if (rand() % 7) //随机抛出异常来模拟异常发生
{
throw 123;
}
}
catch(...)
{
//do something
t.join();
abort(); //终止主线程
}
t.join(); //未发生异常时使用
cout << "主线程main执行结束!" << endl;
return 0;
}

2.png

2、为了应对忘记使用join()和选择位置的问题,可以使用RAII机制来管理子线程,在RAII析构中调用join()。这样在我根本不需要考虑join的位置问题,还是是否忘记的问题。但是这个方式在程序异常的情况下并不能保证主线程被终止时,子线程执行结束。因为程序因异常而终止时,如果没有捕获,对象的析构不会发生,只能由系统来回收资源。关于RAII:cpp中的RAII机制

使用RAII在析构中调用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
#include <thread>
#include <iostream>

using namespace std;

void func()
{
cout << "子线程func开始执行!" << endl;
//do something
int i = 100000 ;
while(i--) { }
cout << "子线程func执行结束!" << endl;
}

class RAII_thread
{
thread& t;
public:
explicit RAII_thread(thread& t_): t(t_) { }
~RAII_thread(){
if(t.joinable())
t.join();
}
RAII_thread(RAII_thread const&) = delete;
RAII_thread& operator=(RAII_thread const&) = delete;
};



int main()
{
//确保异常发生时,子线程执行完毕的技巧2,使用RAII管理子线程
cout << "主线程main开始执行!" << endl;
thread t(func);
RAII_thread raii(t);
//do something
cout << "主线程main执行结束!" << endl;
return 0;
}

3.png