Cpp 多线程:线程
std::thread
是 C++11 中对线程的封装
1 |
基础示例
定义两个函数用于双线程模拟
1 | void function1() { |
使用std::thread
创建两个线程
1 | int Test_MyThread() { |
输出:
1 | >>> Inside function2Inside function1 |
创建线程
std::thread
的构造函数如下:
1 | thread() noexcept; // 默认构造函数,不表示任何线程 |
一般使用的都是最后一个,传参构建线程
两种传参方式
传参有两种方式:值传递和引用传递
- 对于值传递:
std::thread(FunctionName, args)
- 对于引用传递,需要使用
std::ref
或std::cref
封装,std::thread(FN, std::ref(args))
join
和 detach
对于创建的线程,一般会在销毁前调用join
和detach
join
:阻塞调用者所在线程,直至被*this
表示的线程完成执行- 只有活动状态的线程才能调用
join
,即joinable()==true
- 默认构造函数创建的对象为
joinable()==false
join
被调用一次就会变为joinable()==false
,表示线程执行完毕- 调用
terminate()
的线程必须是joinable()==false
- 如果线程不调用
join
,就算执行完成也是一个活动线程,即joinable()==true
- 只有活动状态的线程才能调用
detach
:将thread
对象和其表示的执行线程分离,*this
将不再拥有任何线程- 分离之后,线程单独执行,直到执行完毕并释放资源
- 分离之后,
thread
不再表示任何线程,且joinable()==false
,即使线程此时还在执行
获取线程 ID
每个线程都有一个标识符,可以通过两种方式获取:
thread_obj.get_id();
std::this_thread::get_id();
空 thread()
对象,即不表示任何线程的 thread_obj
调用 get_id()
结果为 0
1 | // 创建线程 |
输出结果:
1 | Thread 1 ID before detach: 29868 |
detach 后,修改的线程 id 只是 thread_obj 内部记录的,和线程本身无关
1 | void function1() { |
输出结果:
1 | Thread 1 ID(inside function1): 29868 |
交换两个thread
对象表示的线程
thread::swap
的实现:
1 | void swap(thread& _Other) |
用例:
1 | int main() { |
输出结果:
1 | before swap: thread_1 id: 32340 thread_2 id: 26796 |
问题汇总
创建线程后,如果既不join
也不detach
,会发生什么?
简单的的解释:
在std::thread
的析构函数中:
1 | ~thread() noexcept { |
调用join
或detach
会把thread
对象的joinable
置为false
。如果都不调用,线程在析构的时候就会调用terminate()
从而使得程序退出。
更深层的分析见链接:C++ 在声明一个线程之后不写 join() 函数或者 detach() 函数,程序就会报错,这是为什么呢?
线程抛出异常无法被常规的try-catch
捕获
参考链接:https://murphypei.github.io/blog/2017/08/cpp11-multithread.html
1 | try |
需要在线程内捕获并保存在一个可以之后访问的结构内
1 | std::mutex g_mutex; |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Fubuki の Donuts!