在boost :: asio :: async_connect上等待超时失败(std :: future :: wait_for)

时间:2015-07-21 10:13:37

标签: c++11 boost-asio

我正在使用std::futureboost::asio::async_connect,以便在发生超时时取消操作,如下所示:https://stackoverflow.com/a/30428941

但是,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

1 个答案:

答案 0 :(得分:3)

这似乎是Stephan Lavavej回答here的错误。

我无法找到原始错误,但已将其修复为&#34; RTM版本&#34; (假设VS2013)。

  

这受内部错误编号DevDiv#255669&#34;的影响:   wait_for() / wait_until()请勿阻止&#34;。幸运的是,我收到了修复   来自我们的一个并发运行时开发人员Hong Hong。和我的   当前构建的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()会立即返回而不会阻塞。

基本上,解决方法是在报告延迟

时循环