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 三把锁 ...
随机推荐
- python中的-1
-1单个使用时表示最后一个: >>> [1,2,3,4][-1] 4 表示范围(区间)时,因为是开区间表示方法,如[0:2]是不包括2的所以 [0:-1]只能访问到倒数第二个(不包括 ...
- 使用fddb的测试工具测试自己的检测器
本文是在linux下测试的,首先编译,并安装gnuplot 按照程序给定,将文件放置到对应的文件夹下 #runEvaluate.pl # where gnuplot ismy $GNUPLOT = & ...
- ES6 之reduce的高级技巧
reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值.reduce() 方法接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 ...
- Elasticsearch Java Rest Client API 整理总结 (一)——Document API
目录 引言 概述 High REST Client 起步 兼容性 Java Doc 地址 Maven 配置 依赖 初始化 文档 API Index API GET API Exists API Del ...
- js 边写边出现刚写的内容
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 使用unity3d和tensorflow实现基于姿态估计的体感游戏
使用unity3d和tensorflow实现基于姿态估计的体感游戏 前言 之前做姿态识别,梦想着以后可以自己做出一款体感游戏,然而后来才发现too young.但是梦想还是要有的,万一实现了呢.趁着p ...
- Linux 第五周 实验: 分析system_call中断处理过程
姬梦馨 原创博客 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 使用gdb跟踪分析一个系统调用内核函数 ...
- Practice1小学四则运算
本次实验是做一个自动生成小学四则运算的小程序,对于我来说是检验基础的一次实验,要运用Visual C++来编写完成,“自动生成”第一印象是要用到Random()函数,“加减乘除”则应该用到switch ...
- Daily Scrum - 11/20
好习惯的养成需要两个星期. ——砖家 今天我们小组又进行了一次愉快的例会,可以看到daily scrum在我们小组已经逐渐变成了每日的好习惯.首先对以下一些团队routine达成了共识: 1.spri ...
- 在eclipse中编译调试ns3
1首先把ns3项目导入eclipse 然后把上面的的ns3按照上面的提示即可导入成功. 然后可以运行一下 ./waf configure 2 配置C/C++ Build 右键工程,选择属性 ...