2012-08-23 36 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; 
}