在多线程程序中禁用 boost::asio 上的线程是否安全?
Is it safe to disable threads on boost::asio in a multi-threaded program?
我在 this SO answer 中读到,asio 内部的几个部分周围有锁。
此外,我知道 asio 旨在允许多个线程为单个线程提供服务 io_context
。
但是,如果我只有一个线程为单个 io_context
提供服务,但是 我想在我的应用程序中有超过 1 个 io_context
,禁用线程是否安全(根据 BOOST_ASIO_DISABLE_THREADS
)
即:我有一个 io_context
和一个已进入其 io_context::run()
循环的线程,它正在为多个套接字等提供服务。与这些套接字的所有交互都在上下文中完成该线程的
然后我还有另一个线程,另一个 io_context
,和 那个 线程服务 io_context
及其套接字等
线程间通信是使用自定义线程安全队列和用 asio::posix::stream_descriptor
包裹的 eventfd
实现的,它由发起线程写入,然后从接收线程读取从线程安全队列中弹出项目。
因此,在任何时候都不会有用户代码尝试从与服务其 asio 对象的 io_context
无关的线程调用 asio 函数。
考虑到上述用例,在 asio 中禁用线程是否安全?
视情况而定。据我所知应该没问题。 caveats/areas关注见下文。
此外,您可能想退后一步,考虑一下目标。如果您正在尝试优化包含异步 IO 的区域,则可能不需要采取如此激烈的措施就能立竿见影。这并不是说在某些情况下,我认为 BOOST_ASIO_DISABLE_THREADS
将有助于挤出一点额外的性能。
影响
BOOST_ASIO_DISABLE_THREADS
所做的是
- 将选定的 mutexes/events 替换为空实现
- 禁用一些内部线程支持(
boost::asio::detail::thread
在构造时抛出)
- 删除原子(atomic_count 变为 non-atomic)
- 使全局变量表现为简单的静态变量(适用于 system_context/system_executor)
- 禁用 TLS 支持
系统执行者
值得注意的是,system_executor
是查询关联处理程序执行程序时的默认回退。库实现指定异步启动将使用所涉及的任何 IO 对象(例如绑定到您的套接字或计时器的执行程序)覆盖默认值。
但是,您必须仔细检查您自己的使用以及 third-party 代码的使用,以确保您不会意外地依赖回退。
Update: turns out system_executor internally spawns a thread_group which uses detail::thread
- correctly erroring out when used
IO 服务
Asio 是可扩展的。一些服务可能选择运行内部线程作为实现细节。
docs:
The implementation of this library for a particular platform may make use of one or more internal threads to emulate asynchronicity. As far as possible, these threads must be invisible to the library user. [...]
我相信库实现会使用 detail::thread
- 如果是这种情况会导致 运行 时间错误。
但是,再次重申,在使用 third-party code/user 服务时,您必须确保它们不会破坏您的假设。
另外,specific operations will not work without the thread support,喜欢:
#define BOOST_ASIO_DISABLE_THREADS
#include <boost/asio.hpp>
#include <iostream>
int main() {
boost::asio::io_context ioc;
boost::asio::ip::tcp::resolver r{ioc};
std::cout << r.resolve("127.0.0.1", "80")->endpoint() << std::endl; // fine
// throws "thread: not supported":
r.async_resolve("127.0.0.1", "80", [](auto...) {});
}
版画
127.0.0.1:80
terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>'
what(): thread: Operation not supported [system:95]
bash: line 7: 25771 Aborted (core dumped) ./a.out
我在 this SO answer 中读到,asio 内部的几个部分周围有锁。
此外,我知道 asio 旨在允许多个线程为单个线程提供服务 io_context
。
但是,如果我只有一个线程为单个 io_context
提供服务,但是 我想在我的应用程序中有超过 1 个 io_context
,禁用线程是否安全(根据 BOOST_ASIO_DISABLE_THREADS
)
即:我有一个 io_context
和一个已进入其 io_context::run()
循环的线程,它正在为多个套接字等提供服务。与这些套接字的所有交互都在上下文中完成该线程的
然后我还有另一个线程,另一个 io_context
,和 那个 线程服务 io_context
及其套接字等
线程间通信是使用自定义线程安全队列和用 asio::posix::stream_descriptor
包裹的 eventfd
实现的,它由发起线程写入,然后从接收线程读取从线程安全队列中弹出项目。
因此,在任何时候都不会有用户代码尝试从与服务其 asio 对象的 io_context
无关的线程调用 asio 函数。
考虑到上述用例,在 asio 中禁用线程是否安全?
视情况而定。据我所知应该没问题。 caveats/areas关注见下文。
此外,您可能想退后一步,考虑一下目标。如果您正在尝试优化包含异步 IO 的区域,则可能不需要采取如此激烈的措施就能立竿见影。这并不是说在某些情况下,我认为 BOOST_ASIO_DISABLE_THREADS
将有助于挤出一点额外的性能。
影响
BOOST_ASIO_DISABLE_THREADS
所做的是
- 将选定的 mutexes/events 替换为空实现
- 禁用一些内部线程支持(
boost::asio::detail::thread
在构造时抛出) - 删除原子(atomic_count 变为 non-atomic)
- 使全局变量表现为简单的静态变量(适用于 system_context/system_executor)
- 禁用 TLS 支持
系统执行者
值得注意的是,system_executor
是查询关联处理程序执行程序时的默认回退。库实现指定异步启动将使用所涉及的任何 IO 对象(例如绑定到您的套接字或计时器的执行程序)覆盖默认值。
但是,您必须仔细检查您自己的使用以及 third-party 代码的使用,以确保您不会意外地依赖回退。
Update: turns out system_executor internally spawns a thread_group which uses
detail::thread
- correctly erroring out when used
IO 服务
Asio 是可扩展的。一些服务可能选择运行内部线程作为实现细节。
docs:
The implementation of this library for a particular platform may make use of one or more internal threads to emulate asynchronicity. As far as possible, these threads must be invisible to the library user. [...]
我相信库实现会使用 detail::thread
- 如果是这种情况会导致 运行 时间错误。
但是,再次重申,在使用 third-party code/user 服务时,您必须确保它们不会破坏您的假设。
另外,specific operations will not work without the thread support,喜欢:
#define BOOST_ASIO_DISABLE_THREADS
#include <boost/asio.hpp>
#include <iostream>
int main() {
boost::asio::io_context ioc;
boost::asio::ip::tcp::resolver r{ioc};
std::cout << r.resolve("127.0.0.1", "80")->endpoint() << std::endl; // fine
// throws "thread: not supported":
r.async_resolve("127.0.0.1", "80", [](auto...) {});
}
版画
127.0.0.1:80
terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>'
what(): thread: Operation not supported [system:95]
bash: line 7: 25771 Aborted (core dumped) ./a.out