Item38 Be aware of varying thread handle destructor behavior

原创 2017年04月29日 23:45:19

   在Item37中解释过一个状态为joinablestd::thread对象其底层对应一个系统线程。std::future对象和std::thread比较类似,一个future对象也对应着一个系统线程。尽管如此这两者在析构的时候其行为也是不一样的。在Item37中已经提到过一个joinable状态的std::thread对象在析构的时候会导致程序terminate,这是因为无论是调用join还是detach都是一个糟糕的行为,这个在Item37中已经进行了解释。而本文所说的std::future对象,它的析构有的时候类似于隐式调用join,有的时候则是类似于隐式调用detach,甚至两者都不是,但是std::future不会导致程序terminate

   既然谈到了std::future,那就来进一步看一下std::future到底是什么东西,这个对象对于在异步编程中有很大的作用,可以异步获取线程的执行结果,相当于是一个channel,用来链接调用者和被调用者,被调用者通常会异步的将结果写入到这个channel中(通常是std::promise),调用者通过std::future对象来获取写入的结果,整个过程如下图:

这里写图片描述

   看到上面这个图,你或许会奇怪,这个结果是保存在哪呢?首先肯定是不能放在std::promise对象的,因为结果可能是在调用future对象获取时早已保存起来了,那么被调用者运行结束会将std::promise析构,如果结果保存在这个对象中那就会导致结果丢失了。那么能否放在std::future对象里面呢? 同样也不行,因为std::future可以用来创建std::shared_future,那么就需要将结果保存在每一个future对象中,会导致这个结果被多次拷贝和复制,或许可以使用引用计数的方式来记录当前有多少个future对象关联到这个结果中,这也不失为一种方法。但是无论是何种方式,都会造成一定的开销,算不上是一个不错的方式。因此C++11将结果保存在一个特殊的位置,这个位置被称为共享状态。可以简单的使用下面这张图来表示它们之间的关系:

这里写图片描述

​这个共享状态很重要,因为std::future对象的析构行为和这个状态息息相关,这也是本文要讨论的主题。

  1. 通过std::async发起的non-deferred策略的task,其返回的std::future,并且是最后一个引用共享状态的,其析构会一直阻塞,直到这个task运行结束,相当于隐式的做了join
  2. 其他形式的std::future对象的析构就是简单的析构,对于异步运行的task来说,这类似于隐式调用detach,对于deferred策略运行的task来说,相当于这个task将不会运行。

   让我们把std::future析构会隐式进行join这个行为进一步细化一下,只要满足下列三个条件的情况,std::future的析构才会是隐式的做join。

  1. 这个std::future是通过std::async创建的,并且引用了一个共享状态
  2. std::async运行任务的时候指定的运行策略是std::launch::async
  3. 这个future对象是最后一个引用共享状态的对象

​   std::future的这种特殊的析构行为让我们的程序行为变得不可预测,特别是我们没有办法知道哪个 future会隐式的join,哪些又是detach,从std::future对象本身来看是无法看出来的。尽管如此,但是我们知道,凡是从std::async创建的std::future都有可能是隐式的join,而其他方式创建的std::future对象则不是,比如通过std::packaged_task创建的std::future,其析构就不会隐式的进行join

版权声明:本文为博主原创文章,未经博主允许不得转载。

HandleThread的分析

一、HandleThread的分析从名称就可以看出,HandleThread是Handle和Thread的‘结合’,但它本质上还是个Thread。 public class HandlerTh...
  • qq_28702545
  • qq_28702545
  • 2016年08月02日 06:47
  • 970

面试behavior questions 回答

1.Tell me about yourself. What the hiring manager really wants is a quick, two- to three-minute s...
  • gxr893571251
  • gxr893571251
  • 2016年02月19日 09:15
  • 469

Handle----Thread-----Runnable------使用的几种情况

参考网址: http://www.cnblogs.com/playing/archive/2011/03/24/1993583.html 1、基础知识 Handler在andro...
  • hfreeman2011
  • hfreeman2011
  • 2012年07月13日 16:01
  • 8055

C++11 thread::native_handle(6)

原文地址:http://www.cplusplus.com/reference/thread/thread/native_handle/ public member function ...
  • guang_jing
  • guang_jing
  • 2014年09月04日 18:55
  • 2085

精通cobol--9.4.1 PERFORM VARYING语句的使用方法

     PERFORM VARYING语句的基本格式如下所示。PERFORM …VARYING …FROM …BY…UNTIL  …其中,“…”部分则是相应的变量,根据具体的不同情况而有所不同。q ...
  • COBOL_OS
  • COBOL_OS
  • 2008年04月20日 12:57
  • 2825

Android Thread,Handler,Loop,Message,HandlerThread总结

问题: 1:Handle Thread Loop,MessageQueue的关系,他们是如何绑定的?2:怎么指定线程处理Handle 发送的消息?3:HandlerThread 与Thread 的区...
  • lqb3732842
  • lqb3732842
  • 2017年02月09日 14:50
  • 464

解决Android中Can't create handle inside thread问题

[java] view plaincopyprint? new Thread()   {       public void run()       {     ...
  • fu_zk
  • fu_zk
  • 2013年09月11日 11:09
  • 2854

DO 4 TIMES VARYING word FROM text-word1 NEXT text-word2.

DATA: BEGIN OF numbers,        one   TYPE p LENGTH 8 DECIMALS 0 VALUE 10,        two   TYPE p LENGTH...
  • zhouxu841023
  • zhouxu841023
  • 2010年11月18日 15:50
  • 14805

WebGL之旅(七)varying变量

前面已经说过的变量类型: attribute: 用在顶点着色器中接收顶点相关信息; uniform: 可以同时在顶点着色器和片元着色器中使用,接收无顶点无关的数据。 现在来看一个新的变量类型: var...
  • xufeng0991
  • xufeng0991
  • 2017年07月21日 22:52
  • 339

Windows下实现一个CThread封装类

用法很简单,从这个类“CThread”继承一个子类"MyThread",重写Run函数即可: #include #include #include #include using names...
  • dengxu11
  • dengxu11
  • 2012年01月17日 16:01
  • 4185
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Item38 Be aware of varying thread handle destructor behavior
举报原因:
原因补充:

(最多只允许输入30个字)