[boost.asio]在不同的线程中关闭tcp::socket或tcp::acceptor与I/O线程有什么影响?

3

我可以在不同的线程中关闭tcp::socket,而不是在同步读取线程中吗? 它看起来像这样:

boost::asio::ip::tcp::socket* tcp_socket;  //blocking mode

线程1:

while(true){
   try{
       std::vector<char> read_buffer(10);
       tcp_socket->read_some( boost::asio::buffer( read_buffer ) );
  }
  catch(boost::system::system_error& e){
  //TODO
  break;
  }
}

线程2:

tcp_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
tcp_socket->close();

我看到了tcp::socket的文档。他们说这个对象是线程不安全的。但演示代码似乎运行良好。那么它是否安全呢?tcp::acceptor又如何呢?我能在同一个tcp::acceptor上的多线程中调用close和accept吗?

2个回答

5
文档指出,对于共享对象,tcp::socket 不是线程安全的。不要指望它似乎可以保证始终正常工作。此外,从另一个线程关闭套接字,在套接字层面上,并不是使阻塞的线程解除阻塞的可移植方法。以下是我的建议:
  • 为asio使用异步API。
  • 使用互斥锁来保护套接字,以防止并发访问,或使用asio顺序化对其进行访问。
引用作者在类似问题上的话:

实际上...

在实践中,它可能在asio当前支持的平台上工作。然而,我故意指定了界面,使它不是线程安全的。这是为了允许实现在套接字对象中存储附加状态,而无需显式同步。

如果您想在同一套接字上运行多个并发操作,则安全且可移植的方法是使用异步操作。

**除非您将套接字设置为非阻塞模式。

干杯,Chris


2
只要您保证在关闭后没有其他线程使用tcp_socket,就是安全的。例如,若当thread2尝试关闭线程时,thread1仍处于读取循环中,则会出现竞态条件。
您可以使用线程共享变量来向thread1发信号以退出循环,并使用障碍物确保只有当thread1处于安全状态时才关闭socket。

感谢您的回复。我运行了我的演示代码。没有锁来同步线程1和线程2。在调用tcp_socket->close()之后,线程1捕获到一个"文件结束"异常,并退出。我发现没有任何文档对此做出合理解释。 - Mamrot
没有锁,任何事情都可能发生。你可能在你的平台上只是幸运,但这并不意味着它是可移植的。正如其他答案所强调的那样:任何类型的并发访问(即两个线程同时访问同一个对象)都会导致问题。只有在禁止并发访问的情况下,才能安全地在线程之间共享对象。 - ComicSansMS

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