2012-10-25 35 views
0

目前我們使用的異步值非常大。 假設我有一個函數,確實是這樣的:未來轉換模式

int do_something(const boost::posix_time::time_duration& sleep_time) 
{ 
    BOOST_MESSAGE("Sleeping a bit"); 
    boost::this_thread::sleep(sleep_time); 
    BOOST_MESSAGE("Finished taking a nap"); 

    return 42; 
} 

在某些時候,在代碼中創建它創建了一個未來將由一個packaged_task被設置成一個int值的任務 - 像這樣(worker_queue是一個boost :: ASIO :: io_service對象在這個例子中):

boost::unique_future<int> createAsynchronousValue(const boost::posix_time::seconds& sleep) 
{ 
    boost::shared_ptr< boost::packaged_task<int> > task(
     new boost::packaged_task<int>(boost::bind(do_something, sleep))); 
    boost::unique_future<int> ret = task->get_future(); 

    // Trigger execution 
    working_queue.post(boost::bind(&boost::packaged_task<int>::operator(), task)); 

    return boost::move(ret); 
} 

在代碼另一點我想換這個函數返回一些更高級別的對象也應該是未來。我需要一個轉換函數,它接受第一個值並將其轉換爲另一個值(在我們的實際代碼中,我們有一些分層並執行異步RPC,將期貨返回給響應 - 這些響應應該轉換爲期貨到實際對象,POD甚至無效未來能夠等待或捕獲例外)。因此,這是在這個例子中,轉換功能:

float converter(boost::shared_future<int> value) 
{ 
    BOOST_MESSAGE("Converting value " << value.get()); 
    return 1.0f * value.get(); 
} 

然後,我認爲是在加速文檔描述只做如果想這種轉換創建一個懶惰的未來:

void invoke_lazy_task(boost::packaged_task<float>& task) 
{ 
    try 
    { 
     task(); 
    } 
    catch(boost::task_already_started&) 
    {} 
} 

然後,我有功能(可能是一個更高層次的API)來創建一個包裹未來:

boost::unique_future<float> createWrappedFuture(const boost::posix_time::seconds& sleep) 
{ 
    boost::shared_future<int> int_future(createAsynchronousValue(sleep)); 
    BOOST_MESSAGE("Creating converter task"); 
    boost::packaged_task<float> wrapper(boost::bind(converter, int_future)); 

    BOOST_MESSAGE("Setting wait callback"); 
    wrapper.set_wait_callback(invoke_lazy_task); 

    BOOST_MESSAGE("Creating future to converter task"); 
    boost::unique_future<float> future = wrapper.get_future(); 

    BOOST_MESSAGE("Returning the future"); 
    return boost::move(future); 
} 

最後我希望能夠利用這樣的:

{  
    boost::unique_future<float> future = createWrappedFuture(boost::posix_time::seconds(1)); 
    BOOST_MESSAGE("Waiting for the future"); 
    future.wait(); 
    BOOST_CHECK_EQUAL(future.get(), 42.0f); 
} 

但是,在這裏我最終得到了一個關於違約承諾的例外。原因似乎對我來說很清楚,因爲執行轉換的packaged_task超出了範圍。

所以我的任務是:我如何處理這種情況。我怎樣才能防止任務被破壞?有這樣的模式嗎?

最好成績,

羅尼

+0

我想創建一個自己的類,它提供了與boost :: ..._ future相同的接口來保存任務,並將所有接口調用委託給任務提供的未來。但是必須有更好的解決方案。 – duselbaer

+0

是否有理由不能包裝正在評估的函數,以便在任務被調用時完成轉換? –

+0

@DaveS主要問題是這些函數是我們軟件中不同圖層的一部分。 createAsynchronousValue方法對應於由RPC消息傳遞層管理的RPC-Request。我會考慮的 ...:) – duselbaer

回答

0

您需要妥善管理任務對象的生命週期。

最正確的方法是從createWrappedFuture()返回boost::packaged_task<float>而不是boost::unique_future<float>。調用者將負責獲取未來對象並延長任務壽命,直到未來的價值準備就緒。

或者您可以像在createAsynchronousValue中那樣將任務對象放入某個「掛起」隊列(全局或類成員)中。但在這種情況下,您需要明確地管理任務生命週期並在完成後將其從隊列中刪除。所以不要認爲這個解決方案對於返回任務對象本身具有優勢。

+0

這就是我想要避免 – duselbaer

+0

@duselbaer你不能避免對象生命週期管理,對不起。 – Rost

+0

當然:)看來,std :: async提供了一個將被執行的任務綁定到它的未來。不幸的是,我們在這裏沒有現代編譯器... – duselbaer