在编译boost时,“threading = multi”究竟是做什么的?

我不完全确定在构buildboost时, threading=multi标志究竟是做什么的。 该文件说:

  Causes the produced binaries to be thread-safe. This requires proper support in the source code itself. 

这似乎不是很具体。 这是否意味着访问,例如,提升容器是由mutexes/locks或类似的守卫? 由于我的代码的性能是至关重要的,我想尽量减less不必要的互斥体等。

一些更多细节:

我的代码是一个插件DLL,它被加载到一个multithreading的第三方应用程序中。 我静态链接升压到DLL(该插件是不允许有除标准的Windows DLL的任何其他依赖项,所以我被迫这样做)。

虽然应用程序是multithreading的,但我的DLL中的大部分函数只能从一个线程调用,因此访问容器不需要保护。 我明确地通过使用boost::mutex和friends来防范我的代码的其余部分,这些代码可以从多个线程中调用。

我已经尝试使用threading=multithreading=single来构buildboost,两者似乎都可以工作,但我真的很想知道我在这里做了什么。

不, threading=multi并不意味着诸如boost容器之类的东西会突然变得对多线程的并发访问是安全的(从性能的角度来看,这将是非常昂贵的)。

相反,它在理论上意味着提升将被编译为线程感知 。 基本上这意味着boost方法和类在从多线程访问时将以合理的默认方式工作,就像std库中的类一样。 这意味着您不能从多个线程访问同一个对象 ,除非另有说明,但您可以安全地从多个线程访问不同的对象。 即使没有明确的支持,这可能看起来很明显,但是如果没有受到保护,库所使用的任何static都会破坏该保证。 使用threading=multi保证任何这样的共享状态是由互斥或其他机制保护的属性。

在过去,我的编译器提供的C和C ++ std库可以使用类似的参数或stdlib flavor,尽管今天大多数情况下只有多线程版本可用。

使用threading=multi进行编译可能会带来很小的负面影响,因为只有有限的静态状态需要同步。 你的意见,你的图书馆大多只会被一个线程调用,并不能激发很多的信心 – 毕竟,这些是潜伏的错误,会让你在一夜之后在凌晨3点被你的老板吵醒长饮的。

boost的shared_ptr的例子是信息性的。 使用threading=single ,甚至不能保证独立处理来自多个线程的两个shared_ptr实例是安全的。 如果他们碰巧指向同一个对象(或者理论上,即使他们不这样做,在一些外来的实现中),也会产生未定义的行为,因为共享状态不会被适当的保护所操纵。

随着 threading=multi ,这不会发生。 但是,从多个线程访问相同的shared_ptr实例仍然不安全 。 也就是说,它没有提供任何线程安全保证,这些保证没有为相关对象记录 – 但它确实给出了独立对象独立的“预期/合理/默认”保证。 这个默认的线程安全级别没有一个好的名字,但实际上现在通常提供所有用于多线程语言的标准库。

作为最后一点,值得注意的是, Boost.Thread隐含地总是使用threading=multi编译 – 因为使用boost的多线程类是隐含的提示,即多线程存在。 使用没有多线程支持的Boost.Thread将是荒谬的。

现在,所有这些都说明了,在编译“带线程支持”或者“没有线程支持”的情况下,这是threading=标志的目的。 在实践中,由于这个标志被引入,多线程已经成为默认,并且单线程异常。 事实上,许多编译器和链接器默认为单线程行为,现在默认为多线程 – 或者至少只需要一个“提示”(例如,在命令行中存在-pthread)来翻转为多线程。

除此之外,还有一个共同的努力,使助推器构建“聪明” – 因为它应该转向多线程模式,当环境有利于它。 这非常模糊,但必然如此。 它和连接pthreads符号一样复杂,因此使用MT或ST代码的决定实际上被推迟到运行时 – 如果pthreads在执行时可用,那么将使用这些符号,否则将不起作用在所有 – 将被使用。

底线是threading=multi是正确的,对于您的场景是无害的,特别是如果您正在生成二进制文件,您将分发到其他主机。 如果你不特别的话,由于构建时间,甚至运行时启发式,它很有可能会工作,但是你运行的时候会默默地使用空的存根方法,或者使用MT-不安全的代码。 使用正确的选项没有什么坏处 – 但是在这个问题的评论中也可以找到一些细节,伊戈尔的回答也是如此。

经过一番挖掘,事实证明, threading=single没有太大的影响,正如人们所期望的那样。 特别是,它不影响BOOST_HAS_THREADS宏,因此不会将库配置为假定单线程环境。

使用gcc threading=multi 只是意味着#define BOOST_HAS_PTHREADS ,而使用MSVC则不会产生任何可见的效果。 特别地, _MT被定义在threading=single _MTthreading=multi模式。

但是请注意,可以通过定义相应的宏(如BOOST_SP_DISABLE_THREADSBOOST_ASIO_DISABLE_THREADS或全局BOOST_DISABLE_THREADS来明确配置Boost库以实现单线程模式。

让我们简洁一点。 Causes the produced binaries to be thread-safe意味着Boost代码适应不同的线程可以使用不同的Boost对象 。 这尤其意味着Boost代码将特别注意访问隐藏的全局或静态对象的线程安全性,这些对象可能会被Boost库的实现所使用。 它不会自动允许不同的线程在没有保护的情况下同时使用相同的Boost对象 (锁/互斥/ …)。

编辑:一些Boost库可能会为特定的函数或类记录一个额外的线程安全。 例如Igor R.在评论中建议的asio::io_service

该文档说明了所需的一切:该选项确保线程安全。 也就是说,在多线程环境下编程时,需要确保某些属性,例如避免对变量的无限制访问。

我认为,启用这个选项是一条路。

进一步参考: 多线程感知模式下的BOOST库