ip :: tcp :: socket.close()线程安全吗?

upd*_*liu 5 boost-asio c++11

如果async_read套接字上有a ,则应该有一个内部线程来io_service检查套接字的状态.socket.close()从另一个线程调用是否安全(也许当它运行一个单独的处理程序时io_service)?

我的意思是即使我可以保证我的处理程序不会同时使用asio socket,它是否足够好(考虑内部线程时io_service)?

更新: 我正在使用async_read堆栈协程.与本文档底部的示例非常相似,只是我的有一个额外的函数层调用yield_context.如果我在该示例中调度socket.close()操作,my_strand整个事情是否安全?换句话说,所有相关的操作(堆栈协程的async_read中间async_read_some,隐式处理程序socket.close())是否会通过单个链运行my_strand

Tan*_*ury 17

通常,对同一套接字对象1进行并发调用是不安全的.该async_read()构成的操作由零个或多个中间的async_read_some()操作.这些中间操作仅在当前正在调用的线程中启动io_service::run().内部线程相当透明,并且特定平台的实现说明中列出的任何线程都不会出现问题.

因此:

  • 如果单个线程正在调用io_service::run()socket.close()从处理程序中调用,那么它是安全的,因为不可能并发执行.文档将此称为隐含链.
  • 如果一个线程正在调用io_service::run(),并socket.close()从处理程序之外调用,那么它是不安全的,因为socket可能有两个并发呼叫: close()从外部io_serviceasync_read_some()从当前调用线程io_service::run().要使其线程安全,请将处理程序发布到io_service调用中socket.close().
  • 如果多个线程正在调用io_service::run(),则需要显式来保证线程安全.在async_read()从内发起的需求strand,而它的完成处理程序也必须包裹在同一条链.此外,socket.close()应通过钢绞线派遣.

对于堆栈协程,使用spawn()接受a 的重载strand将在该上下文中执行提供的函数strand.此外,当yield_context对象作为处理程序传递给异步操作时,处理程序(包括来自组合操作的中间处理程序)在该上下文中被调用strand.因此,为确保线程安全,socket.close()必须:

  • 在协程中调用:

    // The lambda will execute within the context of my_strand.
    boost::asio::spawn(my_strand,
      [socket&](boost::asio::yield_context yield)
      {
        // In my_strand.
        // ...
    
        // The socket.async_read_some() operations that composed async_read()
        // will run within the context of my_strand.
        async_read(socket, ..., yield);
    
        // Still within my_strand.
        socket.close();
      });
    
    Run Code Online (Sandbox Code Playgroud)
  • 明确派发my_strand:

    // The lambda will execute within the context of my_strand.
    boost::asio::spawn(my_strand,
      [socket&](boost::asio::yield_context yield)
      {
        // In my_strand.
        // ...
    
        // The socket_.async_read_some() operations that composed async_read()
        // will run within the context of my_strand.
        async_read(socket, ..., yield);
      });
    
    my_strand.dispatch([socket&](){ socket.close(); });
    
    Run Code Online (Sandbox Code Playgroud)

有关线程安全性,组合操作和线索的更多详细信息,请考虑阅读答案.


1. 修订历史记录了此规则的异常.如果操作系统支持,则同步读取,写入,接受和连接操作是线程安全的.为了完整起见,我在这里包括它,但建议谨慎使用它.