在 boost::asio::async_connect 上等待超时失败 (std::future::wait_for)
Waiting with timeout on boost::asio::async_connect fails (std::future::wait_for)
我正在使用 std::future
和 boost::asio::async_connect
以便在发生超时时取消操作,如此处建议:
但是,std::future::wait_for()
returns 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
这似乎是 Stephan Lavavej here 回答的错误。
我找不到原来的错误,但它已在 "the RTM version" 中修复(假设 VS2013)。
This is affected by internal bug number DevDiv#255669 ":
wait_for()
/wait_until()
don't block". Fortunately, I've received a fix
for this from one of our Concurrency Runtime developers, Hong Hong. With my
current build of VC11, this works:
With my current build of VC11, this works:
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.
I inserted timing code to prove that when wait_for() returns ready, f.get() returns instantly without blocking.
基本上,解决方法是在报告延迟时循环
我正在使用 std::future
和 boost::asio::async_connect
以便在发生超时时取消操作,如此处建议:
但是,std::future::wait_for()
returns 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
这似乎是 Stephan Lavavej here 回答的错误。
我找不到原来的错误,但它已在 "the RTM version" 中修复(假设 VS2013)。
This is affected by internal bug number DevDiv#255669 ":
wait_for()
/wait_until()
don't block". Fortunately, I've received a fix for this from one of our Concurrency Runtime developers, Hong Hong. With my current build of VC11, this works:With my current build of VC11, this works:
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.
I inserted timing code to prove that when wait_for() returns ready, f.get() returns instantly without blocking.
基本上,解决方法是在报告延迟时循环