std :: async保证在return语句之后运行

时间:2015-09-14 14:03:29

标签: c++ c++11 asynchronous

有什么方法可以异步执行一个函数,但保证它会在从当前函数返回后执行?

示例:

   std::future<void> future;
   int do_smth( std::function<void()> callback) 
   { 
       int id = 0;

       auto cb = [=](){ callback(id);};
       future = std::async(std::launch::async, cb);

       return id;
   }

std::async调用应在返回完成后执行。 ASFAIK认为它不能保证发生,执行可能仍然在函数返回之前发生。

[编辑]我想要这个,所以我可以实现观察者模式,如下所示:

class A
{
public:
    void send_request()
    {
        m_id = do_smth( std::bind(&A::on_result,this,_1);
    }

   void on_result(RequestId id) 
   {
      if (id == m_id) {
          // my request finished!
      }
   }
private:
   RequestId m_id;
};

我知道我可以使用一个线程,一个队列,并发布事件但是我想如果我可以使用std::async那么可能会更简单。

1 个答案:

答案 0 :(得分:2)

您的示例将在std::async调用时阻止并等待异步任务完成(因此它完全同步)。

要允许任务继续运行,您需要将返回的未来存储在比该功能更长的变量中,例如,通过从函数返回它,或将它分配给函数外部的一些长期存在的对象:

std::future<void> some_global_future;

int do_smth( std::function<void()> callback) 
{ 
  int id = 0;

  some_global_future = std::async(std::launch::async, callback, id);

  return id;
}

请注意,无需像示例中那样创建lambda。您可以将回调及其参数直接传递给std::async,它们将被复制并传递给新线程,相当于您用于lambda的[=]捕获。

由于您似乎没有使用future返回的std::async,因此另一个选项是使用分离的主题:

int do_smth( std::function<void()> callback) 
{ 
  int id = 0;

  std::thread(callback, id).detach();

  return id;
}

更新:以阻止新线程运行,直到调用者退出,您需要一些同步,例如。

std::mutex mx;

int do_smth( std::function<void()> callback) 
{ 
  int id = 0;
  std::lock_guard<std::mutex> lock(mx);
  auto cb = [=]{ std::lock_guard<std::mutex> l(mx); callback(id); };
  std::thread(cb).detach();

  return id;
}

这可确保callback(id)在锁定互斥锁之前不会发生,这意味着必须返回do_smth

但是,意味着m_id的作业已完成:

    m_id = do_smth( std::bind(&A::on_result,this,_1);

操作系统调度程序可以运行do_smth然后当它返回解锁时互斥锁,运行异步线程,然后在完成后继续运行原始线程并分配给m_id

由于一个线程分配给m_id,而运行回调的线程读取它,因此您将遇到竞争条件。您需要在m_id内设置do_smth来解决此问题。