有什么方法可以异步执行一个函数,但保证它会在从当前函数返回后执行?
示例:
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
那么可能会更简单。
答案 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
来解决此问题。