2014-06-19 34 views
3

我有一個C++ 11程序來檢查數字是否爲素數。程序等待準備好未來的對象。準備就緒後,該程序會告知未來對象的提供者函數是否將該數字視爲素數。C++ 11 future.wait_for()總是返回future_status :: timeout

// future example 
#include <iostream>  // std::cout 
#include <future>   // std::async, std::future 
#include <chrono>   // std::chrono::milliseconds 


const int number = 4; // 444444443 

// a non-optimized way of checking for prime numbers: 
bool is_prime (int x) { 
    for (int i=2; i<x; ++i) if (x%i==0) return false; 
     return true; 
    } 

int main() 
{ 
    // call function asynchronously: 
    std::future<bool> fut = std::async (is_prime, number); 

    // do something while waiting for function to set future: 
    std::cout << "checking, please wait"; 
    std::chrono::milliseconds span (100); 
    //std::chrono::duration<int> span (1); 

    while (fut.wait_for(span)==std::future_status::timeout) { 
     std::cout << '.'; 
     std::cout.flush(); 
    } 

    bool x = fut.get();  // retrieve return value 

    std::cout << "\n"<<number<<" " << (x?"is":"is not") << " prime.\n"; 

    return 0; 
} 

如果你運行程序,你會發現它是一個無限while循環,因爲wait_for()總是返回future_status::timeout,這意味着共享狀態是永遠準備好了。這是什麼原因?我從http://www.cplusplus.com/reference/future/future/wait_for/這個程序,所以我期望它的工作。但是,如果我註釋掉while循環,程序將正常工作。

+0

,因爲它可能是很重要(C++ 11的實現不一定完全穩定):請告訴我們你正在使用的平臺是什麼? – Grizzly

+1

我在使用Ubuntu 13.04和Cygwin 1.7.29時獲得了相同的行爲。看起來問題在於,在我的編譯器中,選擇的默認啓動策略是std :: launch :: deferred,而不是std :: launch :: async。 – user3623874

+2

這顯然是編譯器中的一個bug,與延遲函數一樣,'wait_for'無論如何應該返回'future_status :: deferred'。 – Jarod42

回答

1

不知道這是在編譯器中的錯誤,但我相信wait_for應該返回future_status::deferred 這是Scott Meyers discusses in his bookEffective C++Item 36:Specify std::launch::async if asynchronicity is essential

而且該解決方案,他提出什麼

修復很簡單:只需檢查與std :: async調用相對應的未來,即可查看 任務是否被延遲,如果是,則避免進入基於超時的循環。不幸的是,沒有直接的方法可以問未來其任務是否延期。 相反,你必須調用一個基於超時的函數,比如wait_for。在這種情況下,你並不是真的想等待任何事情,你只是想看看返回值是否是std :: future_status :: deferred,所以在必要的時候扼殺你的溫和懷疑,並以零超時的方式調用wait_for。

在你的情況,你可以更加明確一些異步的@Jarod在他的方案中提到,即使用std::launch::async或者你可以重寫代碼如下

bool x; 
// if task is deferred... 
if (fut.wait_for(std::chrono::milliseconds(0)) == std::future_status::deferred) 
{ 
// ...use wait or get on fut 
// to call is_prime synchronously 
    x = fut.get();  // retrieve return value 
} 
else { // task isn't deferred 
// infinite loop not possible (assuming is_prime finishes) 
while (fut.wait_for(span) != std::future_status::ready) { 
    // task is neither deferred nor ready, 
    // so do concurrent work until it's ready 
    std::cout << '.'; 
    std::cout.flush(); 
} 
// fut is ready 
x = fut.get();  // retrieve return value 
} 

http://coliru.stacked-crooked.com/a/cb4e4b3f642f79f5