使用 RAII 完成线程等待

当使用 std::thread 对象执行线程时,必须要调用 join() (或者 detach(),由于 detach() 可以立即调用,所以这里只考虑 join())

 1 #include <iostream>
 2 #include <thread>
 3 #include <chrono>
 4 
 5 using namespace std;
 6 
 7 void threadInvoker()
 8 {
 9     cout << "thread begin\n";
10     this_thread::sleep_for(chrono::milliseconds(2000));
11     cout << "thread end\n";
12 }
13 
14 void doSomething()
15 {
16     cout << "doSomething begin\n";
17     this_thread::sleep_for(chrono::milliseconds(4000));
18     cout << "doSomething end\n";
19 }
20 
21 void doOther()
22 {
23 }
24 
25 void f()
26 {
27     thread t(threadInvoker);
28 
29     doSomething();
30 
31     doOther();
32     t.join();
33 }
34 
35 int main()
36 {
37     f();
38 }

编译:g++ -std=c++11 -pthread test.cpp

如果 doSomething() 会产生异常,则尝试捕获

 1 #include <iostream>
 2 #include <thread>
 3 #include <chrono>
 4 
 5 using namespace std;
 6 
 7 void threadInvoker()
 8 {
 9     cout << "thread begin\n";
10     this_thread::sleep_for(chrono::milliseconds(2000));
11     cout << "thread end\n";
12 }
13 
14 void doSomething()
15 {
16     cout << "doSomething begin\n";
17     this_thread::sleep_for(chrono::milliseconds(4000));
18     throw 0;
19     cout << "doSomething end\n";
20 }
21 
22 void doOther()
23 {
24 }
25 
26 void f()
27 {
28     thread t(threadInvoker);
29 
30     try {
31         doSomething();
32     }
33     catch (...) {
34         cout << "catch exception\n";
35         t.join();
36         return;
37     }
38 
39     doOther();
40     t.join();
41 }
42 
43 int main()
44 {
45     f();
46 }

但是必须在 catch 块里调用 t.join(),否则会 crash。如果条件一多,很可能会在某个分支下遗忘 t.join()。

因此可以使用 RAII 来避免,在析构函数中进行 join()

 1 #include <iostream>
 2 #include <thread>
 3 #include <chrono>
 4 
 5 using namespace std;
 6 
 7 class ThreadGuard
 8 {
 9 public:
10     explicit ThreadGuard(thread& t):mT(t) {}
11     ~ThreadGuard()
12     {
13         if (mT.joinable()) {
14             cout << "join\n";
15             mT.join();
16         }
17     }
18     ThreadGuard(ThreadGuard const&) = delete;
19     ThreadGuard& operator=(ThreadGuard const&) = delete;
20 private:
21     thread& mT;
22 };
23 
24 void threadInvoker()
25 {
26     cout << "thread begin\n";
27     this_thread::sleep_for(chrono::milliseconds(2000));
28     cout << "thread end\n";
29 }
30 
31 void doSomething()
32 {
33     cout << "doSomething begin\n";
34     this_thread::sleep_for(chrono::milliseconds(4000));
35     throw 0;
36     cout << "doSomething end\n";
37 }
38 
39 void doOther()
40 {
41 }
42 
43 void f()
44 {
45     thread t(threadInvoker);
46     ThreadGuard tg(t);
47 
48     try {
49         doSomething();
50     }
51     catch (...) {
52         cout << "catch exception\n";
53         return;
54     }
55 
56     doOther();
57 }
58 
59 int main()
60 {
61     f();
62 }

利用局部对象的析构保证 join() 的调用

posted @ 2016-10-17 15:41  Kjing  阅读(734)  评论(0编辑  收藏  举报