2014-11-22 260 views
16

我试图确定何时可以安全地拨打wait()std::futurestd::shared_future。我从来没有拨打get()上的future,并且future已经准备好从对其承诺的相应承诺set_value()方法。在std :: future上多次调用wait()并从多个线程安全地调用?

我想等这个future(使用wait()wait_for()wait_until())从多个线程。在promise::set_value()已被呼叫立即返回之后,我也希望拨打wait()

http://www.cplusplus.com/reference/future/future/wait/

调用未来的对象是无效的,在这个成员函数产生不确定的行为

获取从promise一个futurevalid()==true开始其关闭。据我所见,只有future::get()valid()回到假。这个假设是否正确?我可以根据需要经常拨打wait()系列功能吗?诺言的价值设定后,将立即拨打wait()立即返回?我可以从多个线程调用它们吗?

回答

13

从一个承诺得到一个未来启动它关闭有效()==真。据我可以看到只有future :: get()将valid()设置回false。这个假设是否正确?

它也可以通过移动分配一个无效的未来,或通过移动未来使其共享状态转移到不同的对象而变得无效。它不会因为等待而失效。

我可以根据需要经常调用wait()系列函数吗?

是的。

立即返回诺言的值后,将调用wait()吗?

是(这可能涉及到锁定一个互斥体或自旋锁来检查状态准备好,然后返回,这样可能涉及一个小型等待获取锁)

我可以给他们打电话从多个线程?

是的。

wait()是一个const成员函数,所以需要该库确保可以从多个线程中的单个未来对象调用它,而无需用户提供任何同步。

+1

我不确定简单地做一个函数'const'保证它*线程安全*。规范提到这是一个要求吗? – Galik 2014-11-22 14:51:30

+2

我不喜欢使用“线程安全”这个词,因为它对不同的人意味着不同的事情。 17.6.5.9 [res.on.data.races]表示标准库必须确保在一个对象上调用(仅)'const'成员函数不会引入数据竞争。如果对象具有与其他对象共享的状态(如'将来'那样),则库必须提供其自己的同步以防止竞赛。这并不意味着简单地添加'const'就是提供线程安全的magic pixie dust,这意味着库有时需要做额外的工作来为'const'函数提供保证。 – 2014-11-22 14:52:10

+0

简单的事实,'wait()'是'const'只是保证函数不会修改对象的状态。然而,它并不保证结果与其他线程所做的更改保持一致/同步。 – Christophe 2014-11-22 15:05:34

2

从多个线程访问单个future可能会导致数据竞争和未定义的行为,如果其中至少有一个可能执行get()并且没有适当的同步可以避免这种情况。

因此,如果您需要从多个线程访问future,你应该更好地考虑shared_future"They also allow the value in the shared state to be retrieved multiple times once ready."他们是线程安全的,只要每个线程访问使用其自己的shared_future对象的共同未来。

注:我的回答假设在某个时刻一个get()会发生,因为承诺没有明确地提到的是promise<void>

+1

在多个线程中访问结果冲突并可能导致数据竞争,但只是等待共享状态变为就绪状态不会。 OP明确表示“我从未打电话过get()未来”,所以永远不会访问结果。 – 2014-11-22 14:34:10

+0

即使这个问题与这个问题无关,你的第二段可能会被误解,意味着更多的“线程安全”比实际保证的更多。即使您通过不同的'shared_future'对象([futures.state] p11)访问结果,对结果的访问仍然存在冲突。 – 2014-11-22 14:47:16

+1

我同意简单访问wait()不是问题。问题在于访问的继承,因为对一个特定未来实例的成员函数的调用不能保证同步(请参阅“C++并发实践”,等待多个线程,第55页)。 – Christophe 2014-11-22 14:57:22