我正在使用asio同步套接字从后台线程通过TCP读取数据。这封装在“服务器”类中。
但是,我希望线程在调用此类的析构函数时退出。
问题是对任何读取函数的调用都会阻塞,因此线程不能轻易终止。在Win32中有一个API:WaitForMultipleObjects
,这将完全符合我的要求。
我如何通过提升获得类似效果?
答案 0 :(得分:2)
在我们的应用程序中,我们设置“终止”条件,然后使用自身连接到线程正在侦听的端口,以便它被唤醒,注意终止条件并终止。
您还可以检查boost实现 - 如果它们只对套接字执行简单读取(即,不在内部使用WaitForMultipleObjects之类的东西),那么您可能会得出结论,没有任何东西可以简单而干净地解除阻塞线。如果他们在等待多个对象(或完成端口),你可以四处寻找唤醒阻塞线程的能力是否暴露在外面。
最后,你可以杀死线程 - 但你必须超越提升才能做到这一点,并了解后果,例如悬空或泄漏的资源。如果你正在关闭,这可能不是一个问题,取决于该线程正在做什么。
答案 1 :(得分:2)
我发现没有简单的方法可以做到这一点。据说,有办法取消win32 IOCP,但它在Windows XP上运行不佳。 MS确实为Windows Vista和7修复了它。取消asio async_read
或async_write
的推荐方法是关闭套接字。
[析构函数]等待完成处理程序
[完成]如果拆除并且我们因为套接字关闭而失败,通知析构函数完成处理程序已完成。
如果您选择实施此操作,请务必小心。关闭套接字非常简单。 “等待完成处理程序”然而却是巨大的不足。当服务器的线程及其析构函数交互时,可能会出现一些微妙的角落情况和竞争条件。
这非常微妙,我们构建了一个完成包装器(类似于io_service::strand
,只是为了同步取消所有挂起的完成回调。
答案 2 :(得分:1)
最好的方法是创建一个socketpair()
,(boost::asio
用语中的任何内容),将读取器端添加到事件循环中,然后关闭编写器端。你会立刻被那个插座上的eof事件唤醒。
然后线程必须自动关闭。
线程的产生者应该在其析构函数中具有以下内容:
~object()
{
shutdown_queue.shutdown(); // ask thread to shut down
thread.join(); // wait until it does
}
答案 3 :(得分:0)
boost::system::error_code _error_code;
client_socket_->shutdown(client_socket_->shutdown_both, _error_code);
以上代码可帮助我立即关闭同步读取。
答案 4 :(得分:-1)
使用socket.cancel();结束在套接字上阻塞的所有当前异步操作。客户端套接字可能需要在循环中被杀死。我从来没有以这种方式关闭服务器,但你可以使用shared_from_this()并在循环中运行cancel()/ close(),类似于boost聊天示例async_writes到所有客户端的方式。