如果套接字上有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
运行?
答案 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记录了此规则的异常情况。如果操作系统支持,同步读取,写入,接受和连接操作都是线程安全的。为了完整起见,我将其包含在此处,但建议谨慎使用。