ip :: tcp :: socket.close()线程安全吗? [英] Is ip::tcp::socket.close() thread safe?
问题描述
如果套接字上有一个async_read
,则应该有一个io_service
的内部线程来检查套接字的状态.从另一个线程(也许当它正在运行io_service
的单独处理程序时)调用socket.close()
是否安全?
If there is a async_read
on the socket ongoing, there should be a internal thread of io_service
checking the status of the socket. Is it safe to call socket.close()
from another thread (maybe when it is running a separate handler of the io_service
)?
我的意思是,即使我可以保证我的处理程序也不会同时使用asio socket
,它是否足够好(考虑到io_service
的内部线程时)?
I mean even I can guarantee that my handlers will not use the asio socket
concurrently, is it good enough (when taking the internal threads of io_service
into consideration)?
更新:
我在大量的协程中使用async_read
.与此文档底部的示例非常相似,不同之处是我的有一个额外的功能层,可以使用yield_context
进行调用.如果在该示例中在my_strand
中分派socket.close()
操作,那么整个线程是否安全?换句话说,所有相关操作(async_read
,中间async_read_some
,堆栈式协程的隐式处理程序,socket.close()
)是否都将通过单链my_strand
运行?
Update:
I am using async_read
in a stackful coroutine. Quite similar to the example at the bottom of this doc, except that mine has an extra layer of function calling with the yield_context
. If I dispatch the socket.close()
operation in my_strand
in that example, is the whole thing thread safe? In another word, will all concerned operations (async_read
, intermediate async_read_some
, implicit handlers of the stackful coroutine, socket.close()
) run through a single strand my_strand
?
推荐答案
通常,并发调用同一套接字对象 1 是不安全的.组成的 async_read()
操作由零个或多个中间 async_read_some()
操作.这些中间操作仅在当前正在调用io_service::run()
的线程中启动.内部线程是相当透明的,
In general, it is unsafe to make concurrent calls to the same socket object1. The async_read()
composed operation is composed of zero or more intermediate async_read_some()
operations. These intermediate operations are only initiated in threads that are currently calling io_service::run()
. The internal threads are fairly transparent, and none of the threads listed in the Platform-Specific Implementation Notes will present a problem.
因此:
- 如果单个线程正在调用
io_service::run()
,并且从处理程序中调用socket.close()
,那么这是安全的,因为没有并发执行的可能性.文档将其称为隐性链. - 如果单个线程正在调用
io_service::run()
并且从处理程序外部调用socket.close()
,则它是不安全的,因为socket
可能有两个并发调用:close()
从io_service
外部进行调用,并且当前正在调用io_service::run()
的线程中的async_read_some()
.为了使其线程安全,请将处理程序发布到调用socket.close()
的io_service
中. - 如果多个线程正在调用
io_service::run()
,则显式子链是必需的,以确保线程安全.async_read()
需要从strand
,并且其完成处理程序还必须为用同一条线包裹.此外,socket.close()
应该已调度通过链.
- If a single thread is invoking
io_service::run()
andsocket.close()
is invoked from within a handler, then it is safe as there is no possibility of concurrent execution. The documentation refers to this as an implicit strand. - If a single thread is invoking
io_service::run()
andsocket.close()
is invoked from outside of a handler, then it is unsafe, assocket
may have two concurrent calls:close()
from outside of theio_service
andasync_read_some()
from a thread that is currently callingio_service::run()
. To make it thread safe, post a handler into theio_service
that invokessocket.close()
. - If multiple threads are invoking
io_service::run()
, then an explicit strand is required to guarantee thread safety. Theasync_read()
needs to be initiated from within astrand
, and its completion handler must also be wrapped by the same strand. Furthermore,socket.close()
should be dispatched through the strand.
对于堆栈式协同程序,请使用接受strand
的spawn()
重载将在strand
的上下文中执行提供的功能.此外,当yield_context
对象作为处理程序传递给异步操作时,这些处理程序(包括来自组合操作的中间处理程序)在strand
的上下文中被调用.因此,为了确保线程安全,socket.close()
必须为:
For stackful coroutines, using the spawn()
overload that accepts a strand
will execute the provided function within the context of the strand
. Furthermore, when the yield_context
object is passed as the handler to asynchronous operations, the handlers, including intermediate handlers from composed operations, are invoked within the context of the strand
. Hence, to ensure thread safety, socket.close()
must either be:
-
在协程中调用:
invoked within the coroutine:
// 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();
});
明确分配给<c9>:
explicitly dispatched on 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(); });
有关线程安全,组合操作和线程的更多详细信息,请考虑阅读此答案.
For more details on thread safety, composed operations, and strands, consider reading this answer.
1. 修订历史记录此规则的异常情况.如果操作系统支持,则同步读取,写入,接受和连接操作是线程安全的.为了完整起见,我将其包括在此处,但建议谨慎使用.
1. The revision history documents an anomaly to this rule. If supported by the OS, synchronous read, write, accept, and connection operations are thread safe. I an including it here for completeness, but suggest using it with caution.
这篇关于ip :: tcp :: socket.close()线程安全吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!