boost::asio 使用 post() 时没有调用处理程序,直接调用函数时有效(io_context 有效)
boost::asio no handler called when using post(), works when function called directly (io_context has work)
我正在尝试使用计时器定期触发从应用程序到服务器的请求。调用的函数利用 boost::promise 等待完成(以防手动调用并且需要显示成功状态)。启动时我直接调用该函数并且它没有问题地完成。然后计时器会定期再次调用它,但是当通过 deadline_timer 启动时,承诺永远不会实现。
当通过 .post() 调用时,与服务器的连接打开,但在客户端永远不会触发 handle_connect 处理程序。 io_context 已分配工作。
我已经尝试将承诺移至 ServiceRequest-class 而不是传递引用并将其实现为 class 成员以排除生命周期问题。
我已将整个问题简化为失败代码的最小示例:
(Coliru 上的演示:Working (via direct call), Failing (via post))
class ServiceRequest : public boost::enable_shared_from_this<ServiceRequest>
{
public:
ServiceRequest(boost::asio::io_service& io_service, Client& client, boost::promise<bool>& promise)
: io_service_(io_service),
socket_(io_service_),
client_(client),
promise_(promise)
{}
~ServiceRequest()
{}
void Start()
{
socket_.async_connect(
boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 3005),
boost::bind(&ServiceRequest::handle_connect,
shared_from_this(),
boost::asio::placeholders::error
)
);
}
private:
void handle_connect(const boost::system::error_code& ec)
{
if(!ec)
{
promise_.set_value(true);
boost::asio::async_write(socket_,
boost::asio::buffer("Test"),
boost::bind(&ServiceRequest::close_socket,
shared_from_this())
);
}
else
{
promise_.set_value(false);
}
}
void close_socket()
{
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
socket_.close();
}
boost::asio::io_service& io_service_;
boost::asio::ip::tcp::socket socket_;
Client& client_;
boost::promise<bool>& promise_;
};
class RequestHandler
{
public:
RequestHandler(boost::asio::io_service& io_service, Client& client)
: io_service_(io_service),
client_(client)
{}
~RequestHandler()
{}
bool RequestService()
{
boost::promise<bool> promise;
boost::shared_ptr<ServiceRequest> service_request = boost::make_shared<ServiceRequest>(io_service_, client_, promise);
service_request->Start();
bool result = promise.get_future().get();
return result;
}
private:
boost::asio::io_service& io_service_;
Client& client_;
};
class Client {
public:
Client()
: io_service_(),
work_(io_service_),
thread_group_(),
timer_(io_service_),
request_handler_(io_service_, *this)
{
thread_group_.create_thread(boost::bind(&boost::asio::io_service::run, &io_service_));
}
~Client()
{
io_service_.stop();
thread_group_.join_all();
}
void RequestService()
{
io_service_.post(boost::bind(&RequestHandler::RequestService, &request_handler_)); // <<--- deadlocks at promise.get_future().get()
request_handler_.RequestService(); // <<--- works
timer_.expires_from_now(boost::posix_time::seconds(10));
timer_.async_wait(boost::bind(&Client::RequestService, this)); // <<--- deadlocks at promise.get_future().get()
}
private:
boost::asio::io_service io_service_;
boost::asio::io_service::work work_;
boost::thread_group thread_group_;
boost::asio::deadline_timer timer_;
RequestHandler request_handler_;
};
int main()
{
Client client;
client.RequestService();
return 0;
}
直接调用 request_handler_.RequestService() 时一切正常。 boost::asio 的处理程序跟踪按预期显示:
@asio|1559149650.446538|0*1|socket@00000000007b9d40.async_connect
@asio|1559149650.456538|>1|ec=system:0
@asio|1559149650.456538|1*2|socket@00000000007b9d40.async_send
@asio|1559149650.456538|<1|
@asio|1559149650.456538|>2|ec=system:0,bytes_transferred=5
@asio|1559149650.456538|2|socket@00000000007b9d40.close
@asio|1559149650.456538|<2|
当使用 .post() 或截止时间计时器调用 RequestService() 时,处理程序跟踪器显示:
@asio|1559149477.071693|0*1|io_context@000000000022fd90.post
@asio|1559149477.071693|>1|
@asio|1559149477.071693|1*2|socket@00000000007b9e10.async_connect
因此连接已建立但未触发处理程序,因此没有调用 promise.set_value(bool) 并且整个事情都锁定了。
我做错了什么?
您只有一个线程在调用 io_service::run
。
post()
在 io_service 的线程之一上执行您从 io_service 中提供的函数。您在 io_service 的主循环 (RequestHandler::RequestService
) 中尝试 运行 的函数是一个阻塞函数,它正在等待应该执行的工作履行承诺在 io_service 的主题中。这永远不会完成,因为您已经阻止了 io_service 的线程。
这是您在使用 ASIO 或任何异步框架时需要避免的主要错误之一。永远不要阻塞正在处理您的事件的线程,因为您可能会像这样引入微妙的(或 not-so-subtle)死锁。
我正在尝试使用计时器定期触发从应用程序到服务器的请求。调用的函数利用 boost::promise 等待完成(以防手动调用并且需要显示成功状态)。启动时我直接调用该函数并且它没有问题地完成。然后计时器会定期再次调用它,但是当通过 deadline_timer 启动时,承诺永远不会实现。
当通过 .post() 调用时,与服务器的连接打开,但在客户端永远不会触发 handle_connect 处理程序。 io_context 已分配工作。
我已经尝试将承诺移至 ServiceRequest-class 而不是传递引用并将其实现为 class 成员以排除生命周期问题。
我已将整个问题简化为失败代码的最小示例:
(Coliru 上的演示:Working (via direct call), Failing (via post))
class ServiceRequest : public boost::enable_shared_from_this<ServiceRequest>
{
public:
ServiceRequest(boost::asio::io_service& io_service, Client& client, boost::promise<bool>& promise)
: io_service_(io_service),
socket_(io_service_),
client_(client),
promise_(promise)
{}
~ServiceRequest()
{}
void Start()
{
socket_.async_connect(
boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 3005),
boost::bind(&ServiceRequest::handle_connect,
shared_from_this(),
boost::asio::placeholders::error
)
);
}
private:
void handle_connect(const boost::system::error_code& ec)
{
if(!ec)
{
promise_.set_value(true);
boost::asio::async_write(socket_,
boost::asio::buffer("Test"),
boost::bind(&ServiceRequest::close_socket,
shared_from_this())
);
}
else
{
promise_.set_value(false);
}
}
void close_socket()
{
socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
socket_.close();
}
boost::asio::io_service& io_service_;
boost::asio::ip::tcp::socket socket_;
Client& client_;
boost::promise<bool>& promise_;
};
class RequestHandler
{
public:
RequestHandler(boost::asio::io_service& io_service, Client& client)
: io_service_(io_service),
client_(client)
{}
~RequestHandler()
{}
bool RequestService()
{
boost::promise<bool> promise;
boost::shared_ptr<ServiceRequest> service_request = boost::make_shared<ServiceRequest>(io_service_, client_, promise);
service_request->Start();
bool result = promise.get_future().get();
return result;
}
private:
boost::asio::io_service& io_service_;
Client& client_;
};
class Client {
public:
Client()
: io_service_(),
work_(io_service_),
thread_group_(),
timer_(io_service_),
request_handler_(io_service_, *this)
{
thread_group_.create_thread(boost::bind(&boost::asio::io_service::run, &io_service_));
}
~Client()
{
io_service_.stop();
thread_group_.join_all();
}
void RequestService()
{
io_service_.post(boost::bind(&RequestHandler::RequestService, &request_handler_)); // <<--- deadlocks at promise.get_future().get()
request_handler_.RequestService(); // <<--- works
timer_.expires_from_now(boost::posix_time::seconds(10));
timer_.async_wait(boost::bind(&Client::RequestService, this)); // <<--- deadlocks at promise.get_future().get()
}
private:
boost::asio::io_service io_service_;
boost::asio::io_service::work work_;
boost::thread_group thread_group_;
boost::asio::deadline_timer timer_;
RequestHandler request_handler_;
};
int main()
{
Client client;
client.RequestService();
return 0;
}
直接调用 request_handler_.RequestService() 时一切正常。 boost::asio 的处理程序跟踪按预期显示:
@asio|1559149650.446538|0*1|socket@00000000007b9d40.async_connect
@asio|1559149650.456538|>1|ec=system:0
@asio|1559149650.456538|1*2|socket@00000000007b9d40.async_send
@asio|1559149650.456538|<1|
@asio|1559149650.456538|>2|ec=system:0,bytes_transferred=5
@asio|1559149650.456538|2|socket@00000000007b9d40.close
@asio|1559149650.456538|<2|
当使用 .post() 或截止时间计时器调用 RequestService() 时,处理程序跟踪器显示:
@asio|1559149477.071693|0*1|io_context@000000000022fd90.post
@asio|1559149477.071693|>1|
@asio|1559149477.071693|1*2|socket@00000000007b9e10.async_connect
因此连接已建立但未触发处理程序,因此没有调用 promise.set_value(bool) 并且整个事情都锁定了。
我做错了什么?
您只有一个线程在调用 io_service::run
。
post()
在 io_service 的线程之一上执行您从 io_service 中提供的函数。您在 io_service 的主循环 (RequestHandler::RequestService
) 中尝试 运行 的函数是一个阻塞函数,它正在等待应该执行的工作履行承诺在 io_service 的主题中。这永远不会完成,因为您已经阻止了 io_service 的线程。
这是您在使用 ASIO 或任何异步框架时需要避免的主要错误之一。永远不要阻塞正在处理您的事件的线程,因为您可能会像这样引入微妙的(或 not-so-subtle)死锁。