线程的join与detach
-
join与detach理论上的区别与作用,已在上一篇说明,这里不在赘述。
-
实例
#include<thread> #include<iostream> #include<algorithm> #include<vector> #include<windows.h> class WorkThread { public: void operator()() { std::cout << "worker thread " << std::this_thread::get_id() << "is excecuting" << std::endl; Sleep(1000); } }; int main() { std::vector<std::thread> thread_list; for (int i = 0; i < 10; i++) { thread_list.push_back(std::thread(WorkThread())); } std::cout << "wait for all thread to finish" << std::endl; //use join std::for_each(thread_list.begin(), thread_list.end(), std::mem_fn(&std::thread::join)); //use detach //std::for_each(thread_list.begin(), thread_list.end(), std::mem_fn(&std::thread::detach)); std::cout << "exiting from main thread" << std::endl; system("pause"); return 0; }
-
运行结果:
-
在使用join函数的运行结果
-
-
在使用detach函数的运行结果
-
-
-
分析与拓展
-
被 detached 的线程,自生自灭,不受控制,无法再 join。
-
从join和detach两种方式的运行结果可以看出,子线程调用join后,主线程要在调用位置等待子线程执行完后,(将子线程占用资源释放)再向后继续执行;而在子线程detach情况下,子线程对象与执行线程分离,子线程脱离主线程的控制,各自在执行完后进行资源释放。
-
分析代码:std::thread(WorkThread())
- WorkThread()是调用默认构造函数创建一个无名的WorkThread对象。外层则是调用thread类的构造函数创建一个无名的thread类线程对象并启动该线程,查看STL源码可知thread类构造函数形式为下图,可知thread构造函数形参依次为函数对象(函数名)、函数的形参,其本质是启动线程并执行函数。只不过这里的函数对象不是普通的函数对象,而是仿函数(总结过)对象,最终调用的函数是WorkThread重载出的仿函数,只是仿函数没有形参,对应thread后也就没有对应参数列表。
-
分析代码:std::for_each(thread_list.begin(), thread_list.end(), std::mem_fn(&std::thread::join));
- for_each时c++标准库提供的泛型算法,可以对容器类型的变量中每个元素进行迭代调用函数处理。注意此处的函数地址处调用了stl的men_fn函数(member_function),其作用是适配类的成员函数。整条语句的作用是将所有线程实例均调用join()函数。
- 番外:这里提到适配(顾名思义,就是对原有接口进行封装以适用于新的接口),不得不提一下c++ STL的适配器,关于c++ STL适配器这篇最详尽不过了。
-