推断一个程序是否要使用线程。

问题描述 投票:3回答:1

线程安全或线程兼容的代码是好的。然而在有些情况下,如果知道程序不会使用线程,就可以用不同的方式实现(更简单或更有效)。

例如,我曾经听说过像 std::shared_ptr 可以使用不同的实现来优化非线程情况(但我找不到参考资料)。我认为历史上 std::string 在某些实现中可以在非线程代码中使用Copy-on-write。

我不赞成或反对这些技术,但是 我想知道是否有一种方法,(至少是一种名义上的方法)在编译时确定代码是否正在用 意图 的使用线程。

我最接近的是意识到线程代码通常是(? -pthreads (不是 -lpthreads)编译器选项。不知道是硬性要求还是只是推荐)。

反过来 -pthreads 定义了一些宏,比如 _REENTRANT_THREAD_SAFE,至少在 gccclang.在某些情况下 一些答案 在SO中,我也读到它们已经过时了。

这些宏是否是判断程序是否要和线程一起使用的正确方法?(例如从同一个程序启动的线程)。是否有其他机制可以在编译时进行检测?检测方法的可信度会有多高?


EDIT: 因为这个问题显然可以适用于很多context,所以让我举一个具体的案例。

我正在写一个只用头的库,里面使用了另一个第三方库。我想知道我是否应该将该库初始化为线程安全的(或者至少提供一定程度的线程支持)。如果我假设最大程度的线程支持,但库的用户不会使用线程,那么就会白白付出成本。由于第3个库是一个实现细节,我想我可以根据猜测来决定要求的线程安全级别。

c++ multithreading c++11 pthreads reentrancy
1个回答
2
投票

检测方法会有多大的把握?

不见得。即使你能毫不含糊地检测出代码是否被编译成可用于多线程,也不是所有的东西都必须是线程安全的。

让所有的东西都默认为线程安全,即使它永远只被一个线程使用,也会违背你的方法的目的。如果你不想为你不用的东西买单,你需要更精细的控制来开启线程安全。

如果你的类有一个线程安全和一个非线程安全的版本,那么你可以使用一个模板参数,即

class <bool isThreadSafe> Foo;

并让用户根据具体情况来决定。


1
投票

我支持另一个答案,即线程安全决策最好不要在整个程序的基础上进行,而应该在特定的区域进行。

请注意 boost::shared_ptr 有线程不安全的版本,称为 boost::local_shared_ptr. boost::intrusive_ptr 有安全和不安全的计数器实现。

有些库使用 "null mutex "模式,也就是一个mutex,它对 lock unlock. 请参阅 boost 或 Intel TBB null_mutex或ATL CComFakeCriticalSection. 这是专门用来代替真正的mutex来代替threqad安全的代码,而假的mutex来代替线程不安全的代码。

更有甚者,有时根据当前的执行阶段,以线程安全和线程不安全的方式使用相同的对象可能是有意义的。还有 atomic_ref 的目的是提供对底层类型的线程安全访问,但仍然允许在线程不安全的情况下使用它。

我知道一个在线程安全和线程不安全之间进行运行时切换的好例子。请看 HeapCreateHEAP_NO_SERIALIZEHeapAllocHEAP_NO_SERIALIZE.

我还知道一个有问题的例子。德尔菲建议把它的 BeginThread 封装器 CreateThread API函数。包装器设置了一个全局变量,告诉Delphi内存管理器从现在开始应该是线程安全的。不知道这个行为是否还在,但在Delphi 7中是有的。


有趣的是:在Windows 10中,几乎没有单线程程序。在 main 执行时,静态DLL依赖关系被加载。当前的Windows版本通过使用线程池使DLL加载尽可能的并行化。一旦程序被加载,线程池的线程就会等待其他任务,这些任务可以通过使用Windows API调用或 std::async. 当然,如果程序本身不使用线程和TLS,它不会注意到,但从技术上讲,从操作系统的角度来看,它是多线程的。

© www.soinside.com 2019 - 2024. All rights reserved.