Ожидание с таймаутом на boost::asio::async_connect завершается неудачей (std::future::wait_for)
Я использую std::future
с boost::asio::async_connect
для отмены операции, когда происходит таймаут, как предложено здесь: /questions/48182842/sorcvtime-i-sorcvtimeo-ne-vliyayut-na-operatsii-boostasio/48182850#48182850
Тем не мение, 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 ответ
Похоже, что это ошибка, как здесь ответил Стефан Лававей.
Я не смог найти оригинальную ошибку, но она исправлена в "RTM-версии" (при условии VS2013).
На это влияет внутренний номер ошибки DevDiv # 255669 ":
wait_for()
/wait_until()
не блокируйте ". К счастью, я получил исправление для этого от одного из наших разработчиков Concurrency Runtime, 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() возвращается мгновенно без блокировки.
В основном, обходной путь должен заключаться в цикле, пока он сообщает об отложенном