c++并发编程之thread::join()和thread::detach()
thread::join(): 阻塞当前线程,直至 *this 所标识的线程完成其执行。*this 所标识的线程的完成同步于从 join() 的成功返回。
该方法简单暴力,主线程等待子进程期间什么都不能做。thread::join()会清理子线程相关的内存空间,此后thread object将不再和这个子线程相关了,即thread object不再joinable了,所以join对于一个子线程来说只可以被调用一次,为了实现更精细的线程等待机制,可以使用条件变量等机制。
- #include <iostream>
- #include <thread>
- #include <chrono>
- void foo()
- {
- std::cout << "foo is started\n";
- // 模拟昂贵操作
- std::this_thread::sleep_for(std::chrono::seconds());
- std::cout << "foo is done\n";
- }
- void bar()
- {
- std::cout << "bar is started\n";
- // 模拟昂贵操作
- std::this_thread::sleep_for(std::chrono::seconds());
- std::cout << "bar is done\n";
- }
- int main()
- {
- std::cout << "starting first helper...\n";
- std::thread helper1(foo);
- std::cout << "starting second helper...\n";
- std::thread helper2(bar);
- std::cout << "waiting for helpers to finish...\n" << std::endl;
- helper1.join();
- helper2.join();
- std::cout << "done!\n";
- }
运行结果:
- starting first helper...
- starting second helper...
- foo is started
- waiting for helpers to finish...
- bar is started
- foo is done
- bar is done
- done!
异常环境下join,假设主线程在一个函数f()里面创建thread object,接着f()又调用其它函数g(),那么确保在g()以任何方式下退出主线程都能join子线程。如:若g()通过异常退出,那么f()需要捕捉异常后join.
- #include<iostream>
- #include<boost/thread.hpp>
- void do_something(int& i){
- i++;
- }
- class func{
- public:
- func(int& i):i_(i){}
- void operator() (){
- for(int j=;j<;j++)
- do_something(i_);
- }
- public:
- int& i_;
- };
- void do_something_in_current_thread(){}
- void f(){
- int local=;
- func my_func(local);
- boost::thread t(my_func);
- try{
- do_something_in_current_thread();
- }
- catch(...){
- t.join();//确保在异常条件下join子线程
- throw;
- }
- t.join();
- }
- int main(){
- f();
- return ;
- }
上面的方法看起来笨重,有个解决办法是采用RAII(资源获取即初始化),将一个thread object通过栈对象A管理,在栈对象A析构时调用thread::join.按照局部对象析构是构造的逆序,栈对象A析构完成后再析构thread object。如下:
- #include<iostream>
- #include<boost/noncopyable.hpp>
- #include<boost/thread.hpp>
- using namespace std;
- class thread_guard:boost::noncopyable{
- public:
- explicit thread_guard(boost::thread& t):t_(t){}
- ~thread_guard(){
- if(t_.joinable()){//检测是很有必要的,因为thread::join只能调用一次,要防止其它地方意外join了
- t_.join();
- }
- }
- //thread_guard(const thread_guard&)=delete;//c++11中这样声明表示禁用copy constructor需要-std=c++0x支持,这里采用boost::noncopyable已经禁止了拷贝和复制
- //thread_guard& operator=(const thread_guard&)=delete;
- private:
- boost::thread& t_;
- };
- void do_something(int& i){
- i++;
- }
- class func{
- public:
- func(int& i):i_(i){}
- void operator()(){
- for(int j=;j<;j++)
- do_something(i_);
- }
- public:
- int& i_;
- };
- void do_something_in_current_thread(){}
- void fun(){
- int local=;
- func my_func(local);
- boost::thread t(my_func);
- thread_guard g(t);
- do_something_in_current_thread();
- }
- int main(){
- fun();
- return ;
- }
thread::detach(): 从 thread 对象分离执行的线程,允许执行独立地持续。一旦线程退出,则释放所有分配的资源。调用 detach
后, *this 不再占有任何线程。
- #include <iostream>
- #include <chrono>
- #include <thread>
- void independentThread()
- {
- std::cout << "Starting concurrent thread.\n";
- std::this_thread::sleep_for(std::chrono::seconds());
- std::cout << "Exiting concurrent thread.\n";
- }
- void threadCaller()
- {
- std::cout << "Starting thread caller.\n";
- std::thread t(independentThread);
- t.detach();
- std::this_thread::sleep_for(std::chrono::seconds());
- std::cout << "Exiting thread caller.\n";
- }
- int main()
- {
- threadCaller();
- std::this_thread::sleep_for(std::chrono::seconds());
std::cout << "back to main.\n";
}
运行结果:
- Starting thread caller.
- Starting concurrent thread.
- Exiting thread caller.
- Exiting concurrent thread.
back to main.
如果注释掉main函数里的std::this_thread::sleep_for(std::chrono::seconds(5)); 即不等待independentThread 执行完。运行结果如下:
- Starting thread caller.
- Starting concurrent thread.
- Exiting thread caller.
- back to main.
c++并发编程之thread::join()和thread::detach()的更多相关文章
- 并发编程之Fork/Join
并发与并行 并发:多个进程交替执行. 并行:多个进程同时进行,不存在线程的上下文切换. 并发与并行的目的都是使CPU的利用率达到最大.Fork/Join就是为了尽可能提高硬件的使用率而应运而生的. 计 ...
- 并发编程之fork/join(分而治之)
1.什么是分而治之 分而治之就是将一个大任务层层拆分成一个个的小任务,直到不可拆分,拆分依据定义的阈值划分任务规模. fork/join通过fork将大任务拆分成小任务,在将小任务的结果join汇总 ...
- python并发编程之Queue线程、进程、协程通信(五)
单线程.多线程之间.进程之间.协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯.或者说为了解耦,普遍采用Queue,生产消费模式. 系列文章 python并发编程之threading线程(一 ...
- python并发编程之threading线程(一)
进程是系统进行资源分配最小单元,线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.进程在执行过程中拥有独立的内存单元,而多个线程共享内存等资源. 系列文章 py ...
- 并发编程之:JMM
并发编程之:JMM 大家好,我是小黑,一个在互联网苟且偷生的农民工. 上一期给大家分享了关于Java中线程相关的一些基础知识.在关于线程终止的例子中,第一个方法讲到要想终止一个线程,可以使用标志位的方 ...
- 并发编程之:Atomic
大家好,我是小黑,一个在互联网苟且偷生的农民工. 在开始讲今天的内容之前,先问一个问题,使用int类型做加减操作是不是线程安全的呢?比如 i++ ,++i,i=i+1这样的操作在并发情况下是否会有问题 ...
- 并发编程之:CountDownLatch
大家好,我是小黑,一个在互联网苟且偷生的农民工. 先问大家一个问题,在主线程中创建多个线程,在这多个线程被启动之后,主线程需要等子线程执行完之后才能接着执行自己的代码,应该怎么实现呢? Thread. ...
- 并发编程之wait()、notify()
前面的并发编程之volatile中我们用程序模拟了一个场景:在main方法中开启两个线程,其中一个线程t1往list里循环添加元素,另一个线程t2监听list中的size,当size等于5时,t2线程 ...
- 并发编程之 Exchanger 源码分析
前言 JUC 包中除了 CountDownLatch, CyclicBarrier, Semaphore, 还有一个重要的工具,只不过相对而言使用的不多,什么呢? Exchange -- 交换器.用于 ...
- 并发编程之 Condition 源码分析
前言 Condition 是 Lock 的伴侣,至于如何使用,我们之前也写了一些文章来说,例如 使用 ReentrantLock 和 Condition 实现一个阻塞队列,并发编程之 Java 三把锁 ...
随机推荐
- 20155229《网络对抗技术》Exp6:信息收集与漏洞扫描
实验内容 (1)各种搜索技巧的应用 (2)DNS IP注册信息的查询 (3)基本的扫描技术:主机发现.端口扫描.OS及服务版本探测.具体服务的查点 (4)漏洞扫描:会扫,会看报告,会查漏洞说明,会修补 ...
- 20155235 《网络攻防》 实验九 Web安全基础
20155235 <网络攻防> 实验九 Web安全基础 实验内容 SQL注入攻击 XSS攻击 CSRF攻击 WebGoat WebGoat是OWASP组织研制出的用于进行web漏洞实验的应 ...
- Metasploit简单应用
什么是Metasploit Metasploit是一款开源的安全漏洞检测工具. 它可以帮助用户识别安全问题,验证漏洞的缓解措施,并对某些软件进行安全性评估,提供真正的安全风险情报.当我们第一次接触Me ...
- [c#]记一次实验室局域网的ARP欺骗
起因 某天中午午睡时,笔者被激烈的键盘和鼠标声音吵醒,发现实验室的同学在那边忘我地打LOL,顿觉不爽,于是决定整他一下.想了一下之后觉得就让他掉线一下作为惩罚好了.结合以往的理论知识,大家在同一个局域 ...
- 几种flash存储芯片的用途和分类
1.IIC EEPROM------容量小,采用的是IIC通信协议:用于在掉电时,存系统配置参数,比如屏幕亮度等.常用芯片型号有 AT24C02.FM24C02.CAT24C02等,其常见的封装多为D ...
- python 算法面试题
1.题目是:有一组“+”和“-”符号,要求将“+”排到左边,“-”排到右边,写出具体的实现方法. def StringSort(data): startIndex=0 endIndex=0 count ...
- R语言学习 第二篇:矩阵和数组
向量是一维的,只有行这一个维度,没有其他维度.R可以创建更高维度的数据对象,例如,矩阵.数据框.数组,索引高维度的对象时,需要使用元素的下标.这些对象的下标都使用中括号[]和索引,第一个维度是row, ...
- 基于.NET的3D开发框架/工具比较
好久木有写博客了,这么日子以来忙忙碌碌的,也没大有时间潜心学习和梳理.最近刚好接手一个3D显示的活,虽然还没怎么弄明白,但是也看过一些方案,走了一些弯路,经过一些浅显的了解(3D Display这里面 ...
- numpy 初识(二)
针对 numpy.array(序列)的实例介绍 ndim 数组(矩阵)的维度 size 所有元素的和 数学运算(+, -) 元素个数一样,对应位置相减 加,减,乘,平方一个数,执行广播形式:即都减去一 ...
- Apache Ignite 学习笔记(四): Ignite缓存冗余备份策略
Ignite的数据网格是围绕着基于内存的分布式key/value存储能力打造的.当初技术选型的时候,决定用Ignite也是因为虽然同样是key/value存储,它有着和其他key/value存储系统不 ...