2012-08-23 41 views
1

我一直在忙于Boost的未来,并想知道如果他们是一个可接受和安全的方法来检查一个单独的线程是否已完成。期货是否是检查单个线程完成的安全方法?

我以前从未使用过它们,所以我写的大部分代码都是基于Boost's Synchronization documentation

#include <iostream> 
#include <boost/thread.hpp> 
#include <boost/thread/future.hpp> 

int calculate_the_answer_to_life_the_universe_and_everything() 
{ 
    boost::this_thread::sleep(boost::posix_time::seconds(10)); 
    return 42; 
} 

int main() 
{ 
    boost::packaged_task<int> task(calculate_the_answer_to_life_the_universe_and_everything); 
    boost::unique_future<int> f(task.get_future()); 

    boost::thread th(boost::move(task)); 

    while(!f.is_ready()) 
    { 
     std::cout << "waiting!" << std::endl; 
     boost::this_thread::sleep(boost::posix_time::seconds(1)); 
    } 

    std::cout << f.get() << std::endl; 

    th.join(); 
} 

这似乎等待calculate_the_answer_to_life_the_universe_and_everything()线程返回42.难道事情可能出差错呢?

谢谢!

+0

好了,你可以检查将来的结果是否准备好。我想,产生结果的线程不一定必须终止。 –

+0

当然,忙着等待睡觉并不是正确的做法。不过,您可能将其编写为演示代码。 – usr

回答

2

我一直在忙于Boost的未来,并想知道如果他们是一个可接受的和安全的方法来检查一个单独的线程是否已完成。

期货是异步评估机制,而不是同步机制。尽管某些基元确实具有同步属性(future<>::get),但该库并不旨在与同步,而是激发任务并忽略它,直到需要结果为止。

+2

我不同意,期货被设计为同步。在另一个线程中运行任务很简单,可以安全地将结果提供者与执行代理同步,等待该结果更加困难,并且是期货库的重要组成部分。 –

+0

@JonathanWakely:我可能不够清楚。库的目标不是同步,而是异步执行任务。任务*的异步执行需要*同步(读取结果),但期货没有设计*来同步*。虽然你可以滥用期货,例如通过创建一个'未来',当线程完成时这个值将被设置,并且这是一个唯一目的是同步的用例,'future'并不是最好的工具。 –

+0

这取决于你的意思是“图书馆”和“期货”。 'std :: future'和'std :: shared_future'被设计为同步(但未来的''比'future '做得更好,因为它简单地知道是否完成了某事。)'std :: async'旨在执行任务。 –

4

是的,期货以这种方式使用是安全的,代码是(快速浏览)安全和正确的。

还有其他方法可以做同样的事情(例如,使用atomic_flag或受互斥锁保护的数据或许多其他方法),但是您的代码是执行此操作的有效方法。

N.B.而不是f.is_ready()this_thread::sleep(seconds(1))你可以使用f.wait_for(seconds(1)),一旦结果准备好就会唤醒。这直接等待未来,而不是检查的未来,然后使用一个单独的机制等待,然后检查,然后用一个单独的机制等等待

,取而代之的packaged_taskthread你可以使用async

使用C++ 11名,而不是提升...

int main() 
{ 
    auto f = std::async(std::launch::async, calculate_the_answer_to_life_the_universe_and_everything); 

    while(f.wait_for(std::chrono::seconds(1)) == std::future_status::timeout) 
     std::cout << "waiting!" << std::endl; 

    std::cout << f.get() << std::endl; 
}