本文主要针对join函数,信号量condition_variable、atomic的适用范围和使用方法作介绍
1.join函数
子线程通过调用join函数阻塞主线程,迫使主线程等待子线程执行结束。
1.1join是什么以及join如何使用
- join()函数是一个等待线程函数,主线程需等待子线程运行结束后才可以结束(注意不是才可以运行,运行是并行的),如果打算等待对应线程,则需要细心挑选调用join()的位置
- join的位置十分关键,如果在join之前程序提前结束,那么该线程的资源就不会被释放,造成内存泄露,可以使用C++异常处理机制解决
- 如果线程对象在调用join()函数之前,就已经做完了自己的事情(在构造时传入的方法执行完毕),那么这个函数不会阻塞线程环境,线程环境正常执行。
1.2join与detach
join是指加入主线程,detach则是是子线程从主线程分离。这二者的区别是,主程序会等待调用join的子程序执行完毕,并且资源也会被回收,但不会等待调用detach的子程序只想完毕。执行detach后的子程序可以在后台继续运行。
需要注意的是
- 一个子线程只能调用join()和detach()中的一个,且只允许调用一次。
- 线程创建时候,线程就开始执行,join只不过是迫使主线程等待子线程
1.3join部分参考文章:
【C/C++开发】多线程编程中的join函数 - ZhangPYi - 博客园 (cnblogs.com)
(15条消息) C++11多线程join()和detach()的理解_蚂蚁的希望的博客-CSDN博客_c++ join
(15条消息) c++11中关于std::thread的join函数详解_Geek.Fan的博客-CSDN博客_c++11 join
【C++多线程】join()及注意 - Chen沉尘 - 博客园 (cnblogs.com)
2.信号变量condition_viriable
有时我们会遇到这样的需求:进程B需要进程A达成某种条件之后才可以执行,比如说进程B是去食堂吃饭,进程A为食堂做饭,B就必须等待A完成。那么如何通知B饭菜已经做好了呢?这就是信号变量condition_viriable需要做的。
线程调用condition_viriable下的wait函数阻塞进程,直到另一个线程对同一个condition_viriable调用notify_*函数,线程重新执行。
在食堂的例子中,condition_viriable就好比饭菜,线程B调用wait,等待吃饭,询问食堂饭菜(condition_viriable)做好了没有,并进入等待状态,食堂做好饭之后,调用notify_*,通知B“做好啦”,B就可以愉快的开始干饭啦。
另外,当线程调用wait函数后,线程将被阻塞,并且自动调用mutex::unlock()释放程序获得的锁,以便其他线程使用该锁,当notify_*被执行后,则自动调用mutex::lock()函数,使得线程回到指向wait前的状态。
2.1notify_*函数
notify_*函数分为两类,notify_all,notify_one。
notify_all唤醒所有等待的进程,如果没有等待进程,则什么也不干。
notify_one唤醒一个等待的进程,如果没有等待进程,则什么也不干,值得注意的是,notify_one具体唤醒哪一个线程,是随机的。
2.3本部分参考文章:
C++11 并发指南系列 - Haippy - 博客园 (cnblogs.com)
3.atomic类型
mutex和condition_variable都可以的解决数据竞争的问题,但是上锁解锁的过程很慢,当我们追求极致的运行速度时,我们希望尽可能避免使用mutex和condition_variable,atomic就是为了这一目的产生的。
atomic类型是原子数据类型,多个线程使用该类型时不必担心产生数据竞争,是安全的,而对一般的数据类型而言,多线程同时操作而不使用mutex或者condition_variable将导致undifined的后果。
3.1参考文章
C++11 并发指南六( 类型详解二 std::atomic ) - Haippy - 博客园 (cnblogs.com)