c++11线程介绍
- 在c++11标准线程库之前的相关线程库:要么是属于某个单独平台的,例如:POSIX线程库pthread(Linux),Windows线程库(Windows winapi);要么需要第三方库支持,如第三方数据库:Boost线程库。
- 线程与进程显著区别:不同线程间可共享同一地址资源(内存、全局变量);不同的进程间拥有独立的地址空间,相互间不共享。
- 线程的几个状态
- 在一个线程的生存期内,可以在多种状态之间转换,不同的操作系统可以实现不同的线程模型,定义许多不同的线程状态,每个状态还可以包含多个子状态,但大体来说,如下几种状态是通用的:
- 就绪:参与调度,等待被执行,一旦被调度选中,立即开始执行
- 运行:占用CPU,正在运行中
- 休眠:暂不参与调度,等待特定事件发生
- 中止:已经运行完毕,等待回收线程资源(此时占用资源并没有释放)
- c++11线程的产生:
- 一个进程发起后,会首先生成一个缺省的线程,通常称这个线程为主线程,C/C++程序中,主线程就是通过main函数进入的线程,由主线程衍生的线程成为从线程,从线程也可以有自己的入口函数,相当于主线程的main函数,这个函数由用户指定。通过thread类的构造函数中传入函数实现,在指定线程入口函数时,也可以指定入口函数的参数。
- 主线程与子线程的关系(join与detach的实例在下一篇中记录):
- 无论子线程执行完毕与否,一旦主线程执行完毕退出,所有子线程执行都会终止。这时整个进程结束或僵死,部分线程保持一种终止执行但还未销毁的状态,而进程必须在其所有线程销毁后销毁,这时进程处于僵死状态,为了防止这种现象出现必须使用join或detach。
- 线程函数执行完毕退出,或以其他非常方式终止,线程进入终止态,但是为线程分配的系统资源不一定释放,可能在系统重启之前,一直都不能释放,终止态的线程,仍旧作为一个线程实体存在于操作系统中,什么时候销毁,取决于线程属性。而线程属性是由join()和detach()决定的:
- join函数(汇合线程):当使用join()函数时,主调线程阻塞,等待被调线程终止,然后主调线程回收被调线程资源,并继续运行;
- detach函数(分离线程):当使用detach()函数时,主调线程继续运行,被调线程驻留后台运行,主调线程无法再取得该被调线程的控制权。当主调线程结束时,由运行时库负责清理与被调线程相关的资源。
- join与detach都是保证线程正常退出并回收所占资源,区别在于两者是否阻塞主调线程。
- 注意:
- 不能在程序中既不使用join()合并线程也不使用detach()分离线程,否则线程所占资源无法正常释放
- 在调用join()或detach()前,需要检查线程是否是join-able的。
- 如当join()函数在线程对象上执行,当join()返回时,std::thread 对象与他没有关联线程,如果在这样的对象上再次调用join()函数,那么它将导致程序终止。
类似的,调用detach()使std::thread对象没有链接任何线程函数,在这种情况下,在一个std::thread对象上调用detach()函数两次将导致程序终止。简单地讲就是不要重复join和detach。 - 为了确保join和detach函数是作用在join-able线程上的,在调用以上函数时对线程对象进行joinable()判断,如:
std::thread threadObj(WorkerThread())
if(threadObj.joinable()){
std::cout<<"Detaching Thread"<<std::endl;
threadObj.detach();
}
if(threadObj.joinable()){
std::cout<<"Detaching Thread"<<std::endl;
threadObj.detach();
}