2015-07-21 53 views
2

我以取消操作时发生超时,用std::futureboost::asio::async_connect的建议在这里:https://stackoverflow.com/a/30428941与超时升压等待:: ASIO :: async_connect失败(STD ::未来:: wait_for)

但是,std::future::wait_for()立即返回std::future_status::deferred,即操作尚未开始。后面的conn_result.get()会阻塞,直到因为远程主机未在侦听而导致连接错误。我不想依赖它,因为它可能会持续很长时间,直到出现套接字错误。

如何在boost :: asio创建的期货上正确等待?

编辑:SSCCE

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

using boost::asio::ip::tcp; 

int main(int argc, char* argv[]) { 
    boost::asio::io_service ioservice; 
    boost::asio::io_service::work work(ioservice); 

    std::thread t([&](){ioservice.run();}); 

    tcp::resolver resolver(ioservice); 
    tcp::resolver::query query("127.0.0.1","27015"); // random unused adress 

    tcp::socket socket(ioservice); 

    std::future<tcp::resolver::iterator> conn_result = boost::asio::async_connect(socket,resolver.resolve(query),boost::asio::use_future); 

    std::cout << "IO Service running: " << (!ioservice.stopped() ? "y":"n") << std::endl; 
    auto status = conn_result.wait_for(std::chrono::milliseconds(500)); 
    if (status == std::future_status::timeout) { 
     socket.cancel(); 
     std::cout << "Timeout" << std::endl; 
     return 0; 
    } else if(status == std::future_status::deferred) { 
     std::cout << "Deferred" << std::endl; 
    } 
    // If the operation failed, then conn_result.get() will throw a 
    // boost::system::system_error. 
    try { 
     conn_result.get(); 
    } catch(const boost::system::system_error& e) { 
     std::cerr << e.what() << std::endl; 
    } 


    ioservice.stop(); 
    t.join(); 

    return 0; 
} 
  • 编译:MSVC2012
  • 升压1.58
+2

请发表SSCCE – sehe

+1

'的std :: future_status :: deferred'并不意味着任务还没有开始,就意味着它不是直到你明确地调用'get()'或'wait()',然后它会在当前线程上同步运行。如果任务应该异步运行(async_connect建议),那么Asio应该使用std :: launch :: async策略调用std :: async()来防止延迟。 –

+1

@sehe好点,编辑。 – TheBender

回答

3

这似乎是一个错误的史蒂芬Lavavej回答here

我无法找到原始错误,但它在“RTM版本”(假设VS2013)中已修复。 “: wait_for()/wait_until()不阻止”

这是由内部的bug数DevDiv#255669的影响。幸运的是,我从我们的一位并发运行时开发人员洪虹那里得到了一个修复程序 。随着我 VC11的当前版本,这个工程:

与我目前的VC11的建设,这个工程:

C:\Temp>type meow.cpp 
#include <stdio.h> 
#include <chrono> 
#include <future> 
#include <thread> 
#include <windows.h> 
using namespace std; 

long long counter() { 
    LARGE_INTEGER li; 
    QueryPerformanceCounter(&li); 
    return li.QuadPart; 
} 

long long frequency() { 
    LARGE_INTEGER li; 
    QueryPerformanceFrequency(&li); 
    return li.QuadPart; 
} 

int main() { 
    printf("%02d.%02d.%05d.%02d\n", _MSC_VER/100, _MSC_VER % 100, _MSC_FULL_VER % 100000, _MSC_BUILD); 

    future<int> f = async(launch::async, []() -> int { 
     this_thread::sleep_for(chrono::milliseconds(250)); 

     for (int i = 0; i < 5; ++i) { 
      printf("Lambda: %d\n", i); 
      this_thread::sleep_for(chrono::seconds(2)); 
     } 

     puts("Lambda: Returning."); 
     return 1729; 
    }); 

    for (;;) { 
     const auto fs = f.wait_for(chrono::seconds(0)); 

     if (fs == future_status::deferred) { 
      puts("Main thread: future_status::deferred (shouldn't happen, we used launch::async)"); 
     } else if (fs == future_status::ready) { 
      puts("Main thread: future_status::ready"); 
      break; 
     } else if (fs == future_status::timeout) { 
      puts("Main thread: future_status::timeout"); 
     } else { 
      puts("Main thread: unknown future_status (UH OH)"); 
     } 

     this_thread::sleep_for(chrono::milliseconds(500)); 
    } 

    const long long start = counter(); 

    const int n = f.get(); 

    const long long finish = counter(); 

    printf("Main thread: f.get() took %f microseconds to return %d.\n", 
     (finish - start) * 1000000.0/frequency(), n); 
} 


C:\Temp>cl /EHsc /nologo /W4 /MTd meow.cpp 
meow.cpp 

C:\Temp>meow 
17.00.50419.00 
Main thread: future_status::timeout 
Lambda: 0 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Lambda: 1 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Lambda: 2 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Lambda: 3 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Lambda: 4 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Main thread: future_status::timeout 
Lambda: Returning. 
Main thread: future_status::ready 
Main thread: f.get() took 2.303971 microseconds to return 1729. 

我插入计时代码,以证明时wait_for()返回就绪,f.get( )立即返回而没有阻塞。

基本上,解决办法是循环,同时它报告递延