[编程基础] C++多线程入门2-连接和分离线程
原始C++标准仅支持单线程编程。新的C++标准(称为C++11或C++0x)于2011年发布。在C++11中,引入了新的线程库。因此运行本文程序需要C++至少符合C++11标准。
2 连接和分离线程
在本章中,我们将讨论std::thread的连接和分离。
2.1 用std::thread::join()连接线程
一旦启动一个线程,则另一个线程可以等待该新线程完成。为此,还需要在std::thread对象上调用join()函数,即
std::thread th(funcPtr);
// Some Code
th.join();
让我们看一个例子,假设主线程必须启动10个工作线程,并且在启动所有这些线程之后,主函数将等待它们完成。连接所有线程后,主函数将继续。
#include <iostream>
#include <thread>
#include <algorithm>
#include <vector>
class WorkerThread
{
public:
void operator()()
{
std::cout << "Worker Thread " << std::this_thread::get_id() << " is Executing" << std::endl;
}
};
int main()
{
// 创建多个线程
std::vector<std::thread> threadList;
for (int i = 0; i < 10; i++)
{
threadList.push_back(std::thread(WorkerThread()));
}
// Now wait for all the worker thread to finish i.e.
// Call join() function on each of the std::thread object
// 现在等待所有工作线程完成,即对每个std::thread对象调用join()函数
std::cout << "wait for all the worker thread to finish" << std::endl;
std::for_each(threadList.begin(), threadList.end(), std::mem_fn(&std::thread::join));
std::cout << "Exiting from Main Thread" << std::endl;
return 0;
}
输出为:
Worker Thread 12616 is ExecutingWorker Thread 10584 is Executing
Worker Thread Worker Thread 14696Worker Thread Worker Thread 15356Worker Thread 11228 is Executing
Worker Thread is Executing is Executing
9528 is Executing
Worker Thread
wait for all the worker thread to finish
Worker Thread 16312 is Executing
14448 is Executing77361908 is Executing
is Executing
Exiting from Main Thread
2.2 使用std::thread::detach()分离线程
分离的线程也称为守护进程/后台线程。要分离线程,我们需要对std::thread对象调用std::detach()函数,即:
std::thread th(funcPtr);
th.detach();
调用detach()之后,std::thread对象不再与实际的执行线程关联。
注意在线程句柄上调用detach()和join()时要小心!!
情况1:永远不要在没有关联执行线程的std::thread对象上调用join()或detach()
std::thread threadObj( (WorkerThread()) );
threadObj.join();
// 这将导致程序终止 It will cause Program to Terminate
threadObj.join();
当在线程对象上调用join()函数时,则当此join返回0时,则std::thread对象没有与其关联的线程。如果再次在该对象上调用join()函数,则将导致终止程序。同样,调用detach()可以使std::thread对象不与任何线程函数链接。在那种情况下,在std::thread对象上调用detach函数两次将导致程序终止。
std::thread threadObj( (WorkerThread()) );
threadObj.detach();
// 这将导致程序终止 It will cause Program to Terminate
threadObj.detach();
因此,在调用join()或detach()之前,我们应该检查每次线程是否可连接,即
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();
}
std::thread threadObj2( (WorkerThread()) );
if(threadObj2.joinable())
{
std::cout<<"Joining Thread "<<std::endl;
threadObj2.join();
}
if(threadObj2.joinable())
{
std::cout<<"Joining Thread "<<std::endl;
threadObj2.join();
}
情况2:不要忘记在具有关联的执行线程的std::Thread对象上调用Join或Detach
如果具有关联的执行线程的std::Thread对象没有调用Join或Detach,则在该对象的析构期间-否则它将终止程序。因为在析构内部-或者它检查线程是否仍然是可联接的,然后终止程序,即
#include <iostream>
#include <thread>
#include <algorithm>
class WorkerThread
{
public:
void operator()()
{
std::cout << "Worker Thread " << std::endl;
}
};
int main()
{
std::thread threadObj((WorkerThread()));
// Program will terminate as we have't called either join or detach with the std::thread object.
// Hence std::thread's object destructor will terminate the program
// 程序将终止,因为我们没有使用std::Thread对象调用Join或Detach。因此std::Thread的对象析构函数将终止程序
return 0;
}
输出为:
Worker Thread
程序崩溃
同样,在发生异常的情况下,我们不应忘记调用join()或detach()。为了防止这种情况,我们应该使用“资源获取初始化”( RESOURCE ACQUISITION IS INITIALIZATION,RAII),即
#include <thread>
#include <iostream>
class ThreadRAII
{
std::thread & m_thread;
public:
ThreadRAII(std::thread & threadObj) : m_thread(threadObj)
{
}
~ThreadRAII()
{
// Check if thread is joinable then detach the thread
// 检查线程是否连接,然后分离线程
if (m_thread.joinable())
{
m_thread.detach();
}
}
};
void thread_function()
{
for (int i = 0; i < 10000; i++);
std::cout << "thread_function Executing" << std::endl;
}
int main()
{
std::thread threadObj(thread_function);
// If we comment this Line, then program will crash
// 如果我们注释此行,则程序将崩溃
ThreadRAII wrapperObj(threadObj);
return 0;
}
输出为:
thread_function Executing
2.3 参考
https://thispointer.com//c11-multithreading-part-3-carefully-pass-arguments-to-threads/
[编程基础] C++多线程入门2-连接和分离线程的更多相关文章
- [编程基础] C++多线程入门6-事件处理的需求
原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 文章目录 6 事件处 ...
- [编程基础] C++多线程入门7-条件变量介绍
原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 文章目录 7 条件变 ...
- [编程基础] C++多线程入门4-数据共享和资源竞争
原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++ 11标准. 4 数据共享和资源 ...
- [编程基础] C++多线程入门5-使用互斥锁解决资源竞争
原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 文章目录 5 使用互 ...
- [编程基础] C++多线程入门8-从线程返回值
原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 8 从线程返回值 8 ...
- [编程基础] C++多线程入门1-创建线程的三种不同方式
原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 1 创建线程的三种不 ...
- [编程基础] C++多线程入门10-packaged_task示例
原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 文章目录 10 pa ...
- [编程基础] C++多线程入门9-async教程和示例
原始C++标准仅支持单线程编程.新的C++标准(称为C++11或C++0x)于2011年发布.在C++11中,引入了新的线程库.因此运行本文程序需要C++至少符合C++11标准. 文章目录 9 asy ...
- [编程基础] C++多线程入门3-小心地将参数传递给线程
原始C++标准仅支持单线程编程.新的C++标准(称为c++11或c++0x)于2011年发布.在c++11中,引入了新的线程库.因此运行本文程序需要C++至少符合c++11标准. 文章目录 3 小心地 ...
随机推荐
- java常用注解校验参数
validation中内置的constraints 注解 描述 @AssertFalse 所注解的元素必须是Boolean类型,且值为false @AssertTrue 所注解的元素必须是Boolea ...
- [Android开发学iOS系列] 快速上手UIKit
快速上手iOS UIKit UIKit是苹果官方的framework, 其中包含了各种UI组件, window和view, 事件处理, 交互, 动画, 资源管理等基础设施支持. 按照前面的介绍, 用U ...
- Ubuntu 环境下安装 Docker
系统要求 Docker目前只能运行在64位平台上,并且要求内核版本不低于3.10,实际上内核越新越好,过低的内核版本容易造成功能不稳定. 用户可以通过如下命令检查自己的内核版本详细信息: $ unam ...
- 后端框架学习-----mybatis(使用mybatis框架遇到的问题)
1.配置文件没有注册(解决:在核心配置文件中注册mapper,注册有三种形式.资源路径用斜杆,包和类用点) <mappers> <!--每一个mapper.xml文件都需要在myba ...
- 亚马逊云 RDB数据故障转移(多可用区)
RDB关系数据库(Relational Database,RDB) 创建名为VPC for RDS的vpc 两个可用区,两组公内网 创建安全组 创建RDS数据库实例用的数据库子网组 创建RDS数据库实 ...
- 基于.NetCore开发博客项目 StarBlog - (19) Markdown渲染方案探索
前言 笔者认为,一个博客网站,最核心的是阅读体验. 在开发StarBlog的过程中,最耗时的恰恰也是文章的展示部分功能. 最开始还没研究出来如何很好的使用后端渲染,所以只能先用Editor.md组件做 ...
- 部署RAID 10
额外添加4块硬盘,用于搭建RAID 10 检查linux的磁盘 [root@local-pyyu ~]# fdisk -l |grep '/dev/sd[a-z]' 磁盘 /dev/sda:21.5 ...
- Python--网络编程学习笔记系列02 附:tcp服务端,tcp客户端
Python--网络编程学习笔记系列02 TCP和UDP的概述: udp通信模型类似于写信,不需要建立相关链接,只需要发送数据即可(现在几乎不用:不稳定,不安全) tcp通信模型类似于打电话,一定要建 ...
- 2流高手速成记(之六):从SpringBoot到SpringCloudAlibaba
咱们接上回 2流高手速成记(之五):Springboot整合Shiro实现安全管理 - 14号程序员 - 博客园 (cnblogs.com) 身边常有朋友说:小项目用PHP.大项目用Java(这里绝无 ...
- 常用CSS样式属性
01.常用样式 1.1.background背景 设置元素背景的样式 background,更好的衬托内容. 属性 描述 值 background 背景属性简写.支持多组背景设置,逗号,隔开 back ...