【问题标题】:Interrupt boost::asio synchronous read?中断 boost::asio 同步读取?
【发布时间】:2009-12-06 23:10:47
【问题描述】:
我正在使用 asio 同步套接字通过 TCP 从后台线程读取数据。这被封装在一个“服务器”类中。
但是,我希望线程在调用此类的析构函数时退出。
问题是对任何读取函数的调用都会阻塞,因此线程不能轻易终止。在 Win32 中,有一个 API:WaitForMultipleObjects 可以完全满足我的要求。
如何使用 boost 实现类似的效果?
【问题讨论】:
标签:
c++
multithreading
boost
network-programming
boost-asio
【解决方案1】:
在我们的应用程序中,我们设置了“终止”条件,然后使用自连接到线程正在侦听的端口,以便唤醒它,记录终止条件并终止。
您还可以检查 boost 实现 - 如果他们只是在套接字上进行简单读取(即,不使用 WaitForMultipleObjects 之类的东西在内部本身),那么您可能会得出结论,没有任何东西可以简单而干净地解除阻塞线。如果他们正在等待多个对象(或完成端口),您可以四处挖掘以查看唤醒阻塞线程的能力是否暴露在外部。
最后,您可以终止线程 - 但您必须在 boost 之外执行此操作,并了解后果,例如悬空或泄漏资源。如果您正在关闭,这可能不是问题,具体取决于该线程正在执行的其他操作。
【解决方案2】:
我没有找到简单的方法来做到这一点。据说有取消win32 IOCP的方法,但是在windows XP上就不行了。 MS确实为windows vista和7修复了它。取消asioasync_read或async_write的推荐方法是关闭套接字。
如果您选择实现此功能,请务必小心。关闭套接字非常简单。然而,“等待完成处理程序”是一种轻描淡写的说法。当服务器的线程与其析构函数交互时,可能会发生一些微妙的极端情况和竞争条件。
这很微妙,我们构建了一个完成包装器(类似于io_service::strand,只是为了处理同步取消所有挂起的完成回调。
【解决方案3】:
最好的方法是创建一个socketpair(),(无论boost::asio 用语是什么),将读取器端添加到事件循环中,然后关闭写入器端。您将立即被该套接字上的 eof 事件唤醒。
然后线程必须自动关闭。
线程的生成器应该在其析构函数中,具有以下内容:
~object()
{
shutdown_queue.shutdown(); // ask thread to shut down
thread.join(); // wait until it does
}
【解决方案4】:
boost::system::error_code _error_code;
client_socket_->shutdown(client_socket_->shutdown_both, _error_code);
以上代码帮助我立即关闭同步读取。
【解决方案5】:
使用 socket.cancel();结束当前阻塞在套接字上的所有异步操作。客户端套接字可能需要在循环中被杀死。我从来不需要以这种方式关闭服务器,但您可以使用 shared_from_this() 并在循环中运行 cancel()/close(),类似于 boost 聊天示例 async_writes 到所有客户端的方式。