C++并发 - Thread 和 Promise

1. thread 和async( )对比之下不提供哪些性质:

  1. Class thread 没有所谓发射策略(launch policy),而是永远尝试着将目标函数启动于一个新线程中。如果无法做到就抛出std::system_error并带有差错码resource_unavailable_try_again
  2. 没有接口可处理线程结果,唯一一个可获得的是独一无二的线程ID
  3. 如果发生异常,但是没有被捕捉于线程内,程序会立刻中止并调用std::terminate( )。 如果想把异常传播到线程外的某个context,必须使用exception_ptr
  4. 必须将线程声明为join( 等待线程结束 ) , detach( 运行于后台而不受任何控制 ),
  5. 如果让线程运行于后台而main( )结束了,则所有线程会被鲁莽而硬性地终止。

2. 当心Detached Thread(卸离后的线程):

  1. 因为丧失了对detached thread的控制,没有轻松的办法可以得知它是否运行,以及运行多久。因此绝对不要让一个detached thread访问任何寿命已经结束的object, 基于这个理由,“以by reference方式传递变量和object”给线程总是有风险,应尽量以by value方式传递。
  2. detached thread应该宁可只访问local copy
  3. 如果detached thread用上了一个global 或static object, 应该做以下事情之一:
    • 确保这些global/static object在被销毁前,所有对它们进行访问的detached thread都结束,或者是不再访问它们。

一种做法是使用condition variable,它让detached thread发信号来说它们已经结束,离开main或调用exit( )之前必须先设置这些condition variable, 然后发信号说可以进行析构了

4. promise object

promise object是future object的配对兄弟,二者都能暂时持有一个shared state,但是future object 允许你取回数据(通过调用get( )),而promise object却是让你提供数据。

promise时用来传递运行结果和异常的一般性机制。

4. 使用方法:

  1. 声明一个promise object, 针对持有值或返回值进行特化,如果二者都是none ,就特化为void: std::promise p;
  2. 将promise object的引用传递给线程中运行的任务
    thread t(DoSomething, ref(p));
    
  3. 在线程中调用set_value( )或者是set_exception( current_exception())。

如果想令shared state在线程确实结束时变为ready, 以确保线程的local object以及其他材料在结果被处理之前所有清除,则最好是调用set_value_at_thread_exit( )或set_exception_at_thread_exit( )

p.set_value(move(s));
p.set_exception(current_exception());
  1. 一旦promise object的shared state存在某个值或某个异常,其状态就转变为ready, 就可以在其他地方去除其内容,但是这个“取出”动作需要借助一个“共享相同shared state”的future object。
    future<string> f(p.get_future());
    
  2. 然后调用future.get( )就可以获得被存储的结果,或者是被存储的异常。 get()会导致block, 直到shared state 变为ready,但是此时该线程并不一定结束,该线程仍然可以继续执行其他语句,甚至存储其他结果放到promise中。

    5. Promise & 多线程

    promise和future并不局限于解决多线程问题,在单线程程序中也可以使用promise只有一个结果值或一个异常。

不能既存储值又存储异常,企图这么做会导致std::future_error

Table of Contents