是否可以在 C++ 中关闭线程安全?
Is it possible to turn off thread safety in C++?
我正在构建一个 IO 密集型分布式系统,我计划使进程无状态,以提供单线程但可扩展的运行时。我用 C 语言和 libuv 开始了这个项目,它工作得很好,性能也很棒。但是,开发需要很多时间,因为 C 需要大量样板代码。
因此,我正在评估 C++ 作为替代方案,但是,我还没有找到任何方法来选择退出线程安全结构,例如 std::shared_ptr
。在 clang
或 gcc
中,有什么方法可以禁用对标准库结构的原子访问,从而拥有一个没有任何 mutex/atomic 开销的单线程进程?
一种方法可能是采用 pre c++11 标准,其中指定的 stl 和语言在许多方面都明确不是线程安全的,例如单例构造。当然,本地平台库提供了启动线程的方法,并提供了线程安全的方法来执行内存分配,但对此的讨论不在问题的范围内。
或者,如果提供的 shared_ptr 太冒犯您,请不要使用它。 "old" stl 的其余大部分不依赖于它,并且不提供任何开箱即用的线程安全。你显然不想看 std::async 和朋友。
关于线程行为背后的唯一其他地方是静态函数变量,即单例和内存管理器 (malloc),尽管这很难避免。
如果进程未链接到 libpthread
,std::shared_ptr
的 libstdc++
实现会自动禁用原子指令。您可以通过 ldd
确认是否属于这种情况。
libuv
的典型构建链接到 libpthread
,因此您将需要一个不这样做的库构建(如果可能的话)。
标准库线程安全:Libstdc++
正如 Florian 所说,libstdc++ 的引用计数的线程安全性取决于程序是否链接到 libpthread,因此单线程程序(或更具体地说,未链接到 libpthread 的程序)会自动禁用线程-安全。 Libstdc++ 在 shared_ptr
、旧的 Copy-on-Write std::string
和 std::locale
初始化中使用引用计数。有几种方法可以强制它不使用非线程安全的引用计数:
- 避免任何 libpthread 依赖,这样 libstdc++ 代码将自动使用单线程模式。
- 使用
--disable-thread=single
重建 GCC,以便重建的 libstdc++ 默认使用单线程模式,即使程序链接到 libpthread。
- 使用 libstdc++ 的
shared_ptr
实现的非标准 属性 来强制非原子引用计数,即使 GCC 不是在单线程模式下构建并且程序链接到 libpthread,请参阅 了解如何做到这一点。这不会影响引用计数在语言环境和 COW 字符串中的其他用途。
标准库线程安全:Libc++
对于 libc++,我认为您需要重建库,将 -DLIBCXX_ENABLE_THREADS=OFF
选项传递给 CMake。这将全局禁用所有线程安全。使用库时不能更改 属性,它在构建 libc++ 时已修复。
核心语言线程安全:GCC 和 Clang
您可以使用 -fno-threadsafe-statics
选项来禁用局部静态变量的线程安全初始化。除非您使用该选项,否则将自动添加使本地静态线程安全初始化的代码,并且与程序是否链接到 libpthread 无关。
我正在构建一个 IO 密集型分布式系统,我计划使进程无状态,以提供单线程但可扩展的运行时。我用 C 语言和 libuv 开始了这个项目,它工作得很好,性能也很棒。但是,开发需要很多时间,因为 C 需要大量样板代码。
因此,我正在评估 C++ 作为替代方案,但是,我还没有找到任何方法来选择退出线程安全结构,例如 std::shared_ptr
。在 clang
或 gcc
中,有什么方法可以禁用对标准库结构的原子访问,从而拥有一个没有任何 mutex/atomic 开销的单线程进程?
一种方法可能是采用 pre c++11 标准,其中指定的 stl 和语言在许多方面都明确不是线程安全的,例如单例构造。当然,本地平台库提供了启动线程的方法,并提供了线程安全的方法来执行内存分配,但对此的讨论不在问题的范围内。
或者,如果提供的 shared_ptr 太冒犯您,请不要使用它。 "old" stl 的其余大部分不依赖于它,并且不提供任何开箱即用的线程安全。你显然不想看 std::async 和朋友。
关于线程行为背后的唯一其他地方是静态函数变量,即单例和内存管理器 (malloc),尽管这很难避免。
如果进程未链接到 libpthread
,std::shared_ptr
的 libstdc++
实现会自动禁用原子指令。您可以通过 ldd
确认是否属于这种情况。
libuv
的典型构建链接到 libpthread
,因此您将需要一个不这样做的库构建(如果可能的话)。
标准库线程安全:Libstdc++
正如 Florian 所说,libstdc++ 的引用计数的线程安全性取决于程序是否链接到 libpthread,因此单线程程序(或更具体地说,未链接到 libpthread 的程序)会自动禁用线程-安全。 Libstdc++ 在 shared_ptr
、旧的 Copy-on-Write std::string
和 std::locale
初始化中使用引用计数。有几种方法可以强制它不使用非线程安全的引用计数:
- 避免任何 libpthread 依赖,这样 libstdc++ 代码将自动使用单线程模式。
- 使用
--disable-thread=single
重建 GCC,以便重建的 libstdc++ 默认使用单线程模式,即使程序链接到 libpthread。 - 使用 libstdc++ 的
shared_ptr
实现的非标准 属性 来强制非原子引用计数,即使 GCC 不是在单线程模式下构建并且程序链接到 libpthread,请参阅 了解如何做到这一点。这不会影响引用计数在语言环境和 COW 字符串中的其他用途。
标准库线程安全:Libc++
对于 libc++,我认为您需要重建库,将 -DLIBCXX_ENABLE_THREADS=OFF
选项传递给 CMake。这将全局禁用所有线程安全。使用库时不能更改 属性,它在构建 libc++ 时已修复。
核心语言线程安全:GCC 和 Clang
您可以使用 -fno-threadsafe-statics
选项来禁用局部静态变量的线程安全初始化。除非您使用该选项,否则将自动添加使本地静态线程安全初始化的代码,并且与程序是否链接到 libpthread 无关。