【发布时间】:2015-07-21 10:13:37
【问题描述】:
我正在使用std::future 和boost::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
【问题讨论】:
-
std::future_status::deferred并不意味着任务还没有开始,这意味着它不会开始,直到你显式调用get()或wait()然后它会在当前同步运行线。如果任务应该异步运行(正如async_connect建议的那样),那么 Asio 应该使用std::launch::async策略调用std::async()以防止它被推迟。 -
@sehe 好点,已编辑。
-
@JonathanWakely 任务通常由
io_service::run()方法执行,该方法在单独的线程中运行,所以我希望这正在处理。修改后应该更清楚。boost::asio和std::future work的示例与我的方式相同,所以我有点困惑为什么上面的代码不起作用。 -
在 GDB 中运行代码(使用 GCC 编译后)它运行良好,我看到 Asio 使用
std::promise notstd::async` 所以应该不可能获得deferred状态(只能来自std::async()创建的未来)所以sehe的答案看起来是正确的,这是实现中的一个错误。
标签: c++11 boost-asio