在多线程程序中禁用 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,喜欢:

Live On Coliru

#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