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

时间:2014-02-01 17:07:05

标签: c++11 boost-asio

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

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

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

1 个答案:

答案 0 :(得分:17)

通常,对同一个套接字对象 1 进行并发调用是不安全的。 async_read()组合操作由零个或多个中间async_read_some()操作组成。这些中间操作仅在当前调用io_service::run()的线程中启动。内部线程相当透明,Platform-Specific Implementation Notes中列出的任何线程都不会出现问题。

因此:

  • 如果单个线程正在调用io_service::run()并且从处理程序中调用socket.close(),则它是安全的,因为不可能并发执行。文档将此称为隐含链。
  • 如果一个线程正在调用io_service::run()并且从处理程序外部调用socket.close(),则它是不安全的,因为socket可能有两个并发调用:close()来自当前正在调用io_service的主题的async_read_some()io_service::run()之外的内容。要使其线程安全,请将处理程序发布到调用io_service。{/ li>的socket.close()
  • 如果多个线程正在调用io_service::run(),则需要显式strand来保证线程安全。 async_read()需要从strand内启动,其完成处理程序也必须由同一条链wrapped。此外,socket.close()应该dispatched通过链。

对于堆栈协程,使用接受strand的{​​{3}}重载将在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();
      });
    
  • 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(); });
    

有关线程安全,编写操作和线索的更多详细信息,请考虑阅读spawn() answer。


<子> 1。 this记录了此规则的异常情况。如果操作系统支持,同步读取,写入,接受和连接操作都是线程安全的。为了完整起见,我将其包含在此处,但建议谨慎使用。