std::get<C++11多线程库>(03): 子线程的完整性

 1 #include <QCoreApplication>
 2 #include <iostream>
 3 #include <thread>
 4 
 5 /*
 6  *  话题:一定要保证新线程结束之前,访问到的数据变量具有有效性。否则会产生未定义的行为和异常。
 7  *      单线程代码中,对象销毁之后再去访问,也会产生未定义行为——不过,线程的生命周期增加了这个问题发生的几率。
 8  *
 9  * 场景1: 线程函数访问的局变量已销毁。
10  *        初始线程的函数已执行完毕,但新线程中使用了 初始函数中局部变量的指针或引用。 这种情况下, 新线程继续访问将导致未定行为。
11  *
12  *
13  * 场景2:新线程使用一个可调用对象作为线程函数,新线程结束前,可调用对象被销毁。
14  *       可调用对象会被复制一份到新线程的内存空间, 如果可调用对象中包含指针或者引用,在原可调用对象被析构后,
15  *        复制到新线程中的副本可调用对象继续使用指针或者引用,将是未定义的。
16  *
17  *
18  * 处理这种情况的常规方法:
19  *        使线程函数的功能齐全,将数据复制到线程中,而非复制到共享数据中。
20  *        如果使用一个可调用的对象作为线程函数,这个对象就会复制到线程中,而后原始对象就会立即销毁。但对于对象中包含的指针和引用还需谨慎。
21  *        使用一个能访问局部变量的函数去创建线程是一个糟糕的主意(除非十分确定线程会在函数完成前结束)。
22  *
23  * 此外,可以通过join()函数来确保线程在函数完成前结束。
24 */
25 struct Obj{
26     Obj(int& i):_i(i){}
27     void operator()(){
28         for (; _i>0; --_i)   //潜在访问隐患:悬空引用
29             std::cout<<"i = "<<_i<<std::endl;
30     }
31 
32 private:
33     int& _i;
34 };
35 int main(int argc, char *argv[])
36 {
37     QCoreApplication a(argc, argv);
38 
39     int x = 10000; //局变量
40     Obj obj(x);
41     std::thread t(obj);
42     //t.join();  //加入式。 等待 新线程的结束,访问变量 x 的引用 _i 不会出问题
43     t.detach();  //分离式。 不等待 新线程的结束, 访问变量 x 的引用 _i 可能会出问题
44 
45     return a.exec();
46 }
原文地址:https://www.cnblogs.com/azbane/p/15334378.html