12

我不完全确定threading=multi标志在构建提升时究竟做了什么。文档说:

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

这似乎不是很具体。这是否意味着对例如 boost 容器的访问受到mutexes/locks或类似的保护?由于我的代码性能至关重要,我想尽量减少任何不必要的互斥锁等。

更多细节:

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

虽然应用程序是多线程的,但我的 DLL 中的大多数函数只从单个线程调用,因此不需要保护对容器的访问。我明确地保护了我的代码的剩余位置,这些位置可以通过 usingboost::mutex和 Friends 从多个线程中调用。

我已经尝试过使用两者来构建提升,threading=multi并且threading=single两者似乎都有效,但我真的很想知道我在这里做什么。

4

4 回答 4

18

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

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

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

threading=multi考虑到只需要同步有限数量的静态状态,使用编译可能几乎没有缺点。你的评论说你的库大部分只会被一个线程调用并不能激发很大的信心——毕竟,这些都是潜在的错误,会导致你在一夜之后在凌晨 3 点被老板叫醒长期饮酒。

boost's 的示例提供了丰富的shared_ptr信息。,threading=single甚至不能保证两个独立的操作shared_ptr从多个线程独立操作两个实例是安全的。如果它们碰巧指向同一个对象(或者,理论上,即使它们没有指向同一个对象),您将产生未定义的行为,因为共享状态不会被适当的保护操作。

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

作为最后一点,值得注意的Boost.Thread是总是隐式编译threading=multi- 因为使用 boost 的多线程类是存在多个线程的隐式暗示。在没有多线程支持的情况下使用Boost.Thread将是荒谬的。

现在,综上所述,以上是编译 boost 背后的理论思想“有线程支持”或“没有线程支持”,这是threading=标志的目的。实际上,自从引入此标志以来,多线程已成为默认设置,而单线程则成为异常。实际上,许多默认为单线程行为的编译器和链接器现在默认为多线程 - 或者至少只需要一个“提示”(例如,在命令行上存在 -pthread)即可切换到多线程。

除此之外,还齐心协力使 boost 构建变得“智能”——当环境有利于它时,它应该切换到多线程模式。这很模糊,但必然如此。它变得像弱链接 pthreads 符号一样复杂,因此使用 MT 或 ST 代码的决定实际上推迟到运行时 - 如果 pthreads 在执行时可用,则将使用这些符号,否则将使用弱链接存根 - 什么都不做根本 - 将被使用。

底线是threading=multi对于您的方案是正确且无害的,特别是如果您正在生成一个二进制文件,您将分发到其他主机。如果您不特别注意,由于构建时甚至运行时启发式方法,它很可能无论如何都会工作,但是您确实有机会默默地使用空存根方法,或者使用 MT 不安全代码。使用正确的选项几乎没有缺点 - 但一些血腥细节也可以在评论中找到,也可以在 Igor 的回复中找到。

于 2014-01-08T09:25:47.263 回答
5

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

使用 gccthreading=multi 只是意味着#define BOOST_HAS_PTHREADS,而使用 MSVC 它不会产生任何可见的效果。特别_MT是在threading=singlethreading=multi模式中定义。

但是请注意,可以通过定义适当的宏(如BOOST_SP_DISABLE_THREADS, BOOST_ASIO_DISABLE_THREADS)或全局使用BOOST_DISABLE_THREADS.

于 2014-01-08T09:34:42.147 回答
2

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

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

于 2014-01-08T12:02:24.423 回答
0

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

我认为,启用此选项是可行的方法。

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

于 2013-12-31T15:55:56.003 回答