有啥可以使静态布尔线程安全的吗?
Posted
技术标签:
【中文标题】有啥可以使静态布尔线程安全的吗?【英文标题】:Is there anything that would make a static bool thread safe?有什么可以使静态布尔线程安全的吗? 【发布时间】:2021-09-20 00:49:33 【问题描述】:我最近遇到了一些运行良好的代码,其中 static bool
在多个线程(单个写入器,多个接收器)之间共享,尽管没有同步。
类似的东西(简化):
//header A
struct A
static bool f;
static bool isF() return f;
;
//Source A
bool A::f = false;
void threadWriter()
/* Do something */
A::f = true;
// Source B
void threadReader()
while (!A::isF()) /* Do something */
对我来说,这种代码有一个竞争条件,即使 bool 上的操作是原子的(在大多数 CPU 上),我们不能保证来自写入线程的写入对读取线程是可见的。但有些人告诉我,f 是static
会有所帮助。
那么,C++11 中有什么东西可以使这段代码安全吗?或者任何与静态相关的东西可以使这段代码工作?
【问题讨论】:
不,这段代码会导致 UB。 std::atomicstd::atomic<T>
在单个对象上提供线程安全操作。如果这足够了,就不需要互斥体,而且原子操作可能会更快。
其实我不太明白这个问题。是不是“这段代码有异味,但它有效。为什么?”还是“这段代码有异味,如何解决?”
【参考方案1】:
您的硬件可能能够以原子方式在bool
上运行。但是,这并不能使此代码安全。就 C++ 而言,您在不同的线程中写入和读取 bool
没有同步,这是未定义的。
将bool
设为静态不会改变这一点。
要以线程安全的方式访问bool
,您可以使用std::atomic<bool>
。 atomic
是否使用互斥锁或其他锁定取决于实现。
尽管std::atomic<bool>
也不足以同步threadReader()
和threadWriter()
,以防每个/*Do something */
访问相同的共享数据。
但有些人告诉我,f 是静态的这一事实会有所帮助。
坦率地说,这听起来像是对货物的***。我可以想象这与静态局部变量的初始化是线程安全的事实混淆了。来自cppreference:
如果多个线程尝试初始化相同的静态本地 变量并发,初始化只发生一次(类似 可以使用 std::call_once 获得任意函数的行为。
注意:此功能的通常实现使用 双重检查锁定模式,它减少了运行时开销 已经初始化的局部静态变量为单个非原子布尔值 比较。
查找 Meyers 单例以查看该示例。虽然,这仅仅是关于初始化。例如这里:
int& foo()
static int x = 42;
return x;
两个线程可以同时调用这个函数,x
将被初始化一次。这对x
本身的线程安全没有影响。如果两个线程调用foo
,一个写入另一个读取x
,则存在数据竞争。但是,这是关于静态局部变量的初始化,与您的示例无关。当他们告诉你static
会“帮助”时,我不知道他们是什么意思。
【讨论】:
这都是正确的。但即使使用std::atomic<bool>
,代码也包含其他错误。使用std::atomic<bool>
并不能充分防止threadWriter
和threadReader
之间的竞争条件。一方面,threadWriter
需要以某种方式等待没有活动的threadReader
。
@FrançoisAndrieux 没有使用store
和load
足够的同步?抱歉,我不确定我是否完全理解代码(以及您的评论)
这里的关键是“hardware may be able to atomically operation on a bool
”中的“atomically”与std::atomic<bool>
中的“atomically”不一样,支持在@987654348上进行原子操作@ 目的。 std::atomic
从 C++ 语言的角度管理潜在的数据竞争,并确保没有数据竞争。
@PeteBecker 这基本上就是我想说的,只是措辞更好;)
@463035818_is_not_a_number 足以避免UB访问flag。但是问题中使用的方案不会同步threadWriter
和threadReader
操作的数据(假设它们接触相同的数据)。如果一个线程调用threadWriter
,而另一个线程正在运行threadReader
,那么没有什么可以阻止共享数据的竞争。以上是关于有啥可以使静态布尔线程安全的吗?的主要内容,如果未能解决你的问题,请参考以下文章
单例实例声明为 GetInstance 方法的静态变量,它是线程安全的吗? [复制]