线程安全地关闭同步使用的boost::asio::ip::tcp::socket

3
鉴于自Boost 1.52.0以来,`boost::asio::ip::tcp::acceptor`和`boost::asio::ip::tcp::socket`都被标记为非线程安全,是否可能从单独的线程关闭当前在`accept()`上阻塞的`tcp::acceptor`?
我尝试调用`boost::asio::io_service::stop()`,这似乎是可行的,因为`io_service`是线程安全的。但这会使`io_service`事件循环保持运行状态,直到对套接字正在进行的任何处理完成为止?
由于这只是一个更大程序中简单的事件循环,我正在同步操作,不想没有充分理由就创建额外的线程,而我知道异步操作会这样做。

1
为什么需要从单独的线程调用 stop()?ASIO 的整个设计理念是应用程序是单线程的。理想情况下,您的事件触发器(回调)之一会调用 stop() - chrisaycock
9
“ASIO 的整个关键在于应用程序是单线程的。”-- 这完全不是真的。 - Galimov Albert
io_service调度处理程序,停止它并不能帮助你。另一方面,从另一个线程关闭接收器将不是线程安全的。唯一安全的方法是使用async_accept,然后在同一个线程中关闭接收器,如果需要的话。 - Igor R.
2
不需要强制要求。由于它不是必需的,因此可以直接使用。许多线程可以运行 io_service::run(),并且处理程序将分派到所有这些线程,因此您可以轻松地获得异步多线程。此外,asio 还有许多简化多线程编程的功能,例如 asio::strand 等。 - Galimov Albert
3个回答

4

如果您的接收器在 async_accept 中,您可以调用 ip::tcp::acceptor::cancel() 取消它上面的任何异步操作。请注意,这可能会触发此接收器中带有 boost::asio::error::operation_aborted 错误代码的处理程序。

如果您正在使用同步的 accept,似乎不可能,因为我认为它与 io_service 没有任何关系。


2
更倾向于使用close,因为cancel不够通用,可能会引起麻烦。请参考以下文章http://www.boost.org/doc/libs/1_52_0/doc/html/boost_asio/reference/basic_socket/cancel/overload1.html(虽然它讨论的是`socket`,但同样适用于`acceptor`)。 - Igor R.
@PSIAIt 我认为有一个解决方案,我在答案中概述了。如果您看了一下并且觉得我是错误的,请告诉我。 - Graeme
@IgorR. 谢谢,我之前不知道这个 Windows 的限制(我只在 Unix 上写代码)。 - Galimov Albert

4

经过一段时间的研究,只有一种线程安全的方式可以实现:通过向套接字发送消息(在不等待accept()的线程上)告诉线程关闭套接字和接收器。这样做可以使套接字和接收器完全由单个线程拥有。

正如另外指出的那样,io_service仅适用于异步操作。


1
好的,这应该有助于阻止情况发生。看起来像是一个hack,但如果你喜欢这样可以的。 - Galimov Albert
2
我得出了相同的结论。太遗憾了,同步接受方式不能像同步读取/读取到某个位置那样被取消。我使用同步调用是因为它们被建议用于简单的应用,但现在我必须重写所有内容,因为遇到了这个问题。我有一种感觉,由于这个调用,应该不鼓励使用同步调用。 - FrozenCow

0

我认为你有点过度思考了。使用非阻塞accept或带有超时条件循环的本地accept,再加上互斥锁就可以实现线程安全。当新连接到达时,你也可以使用本地select和accept。设置超时和条件循环来进行选择。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接