1. 线程管理基础
线程管理的基础
- 每个程序至少都有一个线程
- 各自线程都有自己的入口函数
- 其他线程和main函数线程同时运行
启动线程
-
线程在
std::thread
对象创建时启动void do_some_work();
std::thread my_thread(do_some_work);
-
除了直接使用函数之外,仿函数也可以作为入口函数
class test{
public :
void operator()()const{
...
}
}
test A;
std::thread my_thread(A)
-
代码中提供的函数对象会复制到新线程的存储空间中,函数对象的副本和原始函数对象保持一直
-
注意在使用仿函数作为入口的时候,如果传入临时对象会存在语法解析问题,如下
std::thread my_thread(test())
这个时候C++将上述语句解释为返回值为thread,参数为test对象的函数
如果需要达到我们入口函数的目的可以参考一下写法
std::thread my_thread((test()))
std::thread my_thread{test()}
-
lambda表达式也可作为入口函数
std::thread my_thread([]{...})
-
启动线程后需要明确是等待线程结束(join())还是让线程自主运行(detach())如果在thread对象结束的时候还没有做出决定,程序就会终止
-
如果不等待线程,就必须保证在子线程结束之前,可访问的数据一直有效,使用一个能访问局部变量的函数去创建一个线程是一个糟糕的主意
-
需要在主线程的异常抛出之前调用join()
struct func; void f(){ int state = 0; func my_func(stat); std::thread t(my_func); try{ ...; } catch(...){ t.join(); throw; } t.join(); }
-
为了确定主线程在结束的时候,能够保证等待使用了局部变量的子线程,可以采用如下方法:
class thread_guard{ std::thread & t; public: explicit thread_guard(std::thread & td):t(td){}; ~thread_guard(){if(t.joinable()){t.join()}}; } void f(){ int tmp = 0; std::thread t(my_func,tmp); thread_guard g(t); }
这个时候当tmp走出作用域的时候,t线程对象也会走出作用域,g的析构函数就会自动join() t对象
-
使用detach()会让线程后台运行,这就意味这主线程不能与之产生直接交互
void myfun(); std::thread t(myfunc); t.detach()
参考文献
- 本文档是我在学习C++并发编程时的笔记,参考书籍《C++并发编程》中文版
本文作者:^江流儿^
本文链接:https://www.cnblogs.com/hhyandcpp/p/17020688.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步