当只有一个线程写入 c++ 中的布尔变量时,是否存在争用条件
Is a race condition possible when only one thread writes to a bool variable in c++?
在下面的代码示例中,程序执行永远不会结束。
它创建一个线程,该线程在终止之前等待全局bool
设置为 true
。只有一个作家和一个读者。我相信允许循环继续运行的唯一情况是bool
变量是否为假。
bool
变量怎么可能最终只使用一个编写器处于不一致的状态?
#include <iostream>
#include <pthread.h>
#include <unistd.h>
bool done = false;
void * threadfunc1(void *) {
std::cout << "t1:start" << std::endl;
while(!done);
std::cout << "t1:done" << std::endl;
return NULL;
}
int main()
{
pthread_t threads;
pthread_create(&threads, NULL, threadfunc1, NULL);
sleep(1);
done = true;
std::cout << "done set to true" << std::endl;
pthread_exit(NULL);
return 0;
}
从某种意义上说,这个语句threadfunc1()
存在一个问题:
while(!done);
可以由编译器实现为:
a_register = done;
label:
if (a_register == 0) goto label;
因此,永远不会看到done
的更新。
实际上没有什么可以阻止编译器优化while循环。使用原子或互斥锁从多个线程访问布尔值。这是唯一受支持且正确的解决方案。当您使用 posix 时,在这种情况下,互斥锁将是正确的解决方案。
并且不要使用volatile
.有一个 posix 标准规定了什么必须有效,volatile
不是一个有保证工作的解决方案。
还有一个问题:在将标志设置为 false 之前,无法保证新创建的线程每次都开始运行。
对于这样简单的例子,易失性就足够了。但对于绝大多数现实世界的情况来说,事实并非如此。为此任务使用条件变量。乍一看,它们看起来很奇怪,但实际上它们非常合乎逻辑。在 x86 上,布尔是原子的读/写(对于 ARM,可能不是)。向量也存在一个障碍:它不是布尔值的向量,它是一个位域。要从多个线程写入向量,请使用 vector(或 bool arr[SIZE])。你也没有加入线程,这是错误的。
争用条件意味着:当两个线程访问同一个对象,并且其中至少有一个是写入时。
这意味着您将有两种类型的赛车,写-写冲突和写-读冲突。
回到你的代码,你基本上有两个线程,一个是主线程,另一个是你用pthread_create创建的线程。
其中一个是read: while(!done),另一个是write: done = true。
你肯定有比赛条件。
在 c++ 中只有一个线程写入布尔变量时,是否存在竞争条件?
是的。在您的情况下,主线程也是一个线程(即您有一个线程写入和一个线程读取)。
布尔变量怎么可能最终只用一个编写器处于不一致的状态?
编译器是(应该是)优化编译器。它可能会优化done变量的读取,除非您注意避免这种情况(改用std::atomic<bool> done
)。
不能保证分配给一个字节的布尔值是原子的
- 变量定义到C++布尔值转换
- 如何在 c++ 中让布尔变量返回为 0 或 1 而不是真或假?
- 将布尔变量添加到 int
- 如何使布尔变量仅在设置为 true 时才为真?
- 为什么我不能在返回 const 的布尔函数中为类成员变量赋值?C++
- 创建类似于布尔值的变量类型
- C++中未初始化成员布尔变量的默认值是多少?
- 我可以在C++中延迟布尔变量的求值吗
- 互锁变量访问(在布尔值上)和 std::atomic_flag 之间的区别
- 全局销毁期间全局布尔变量可靠吗?
- 使用动态布尔变量实例化模板
- 如何检查布尔变量是否为真
- C++ 动态评估变量类型布尔值
- 尝试将字符串变量转换为布尔值会导致 "true" 和 "false" 都等于 0
- do while 循环忽略我的布尔标志变量 C++
- 布尔变量 if 语句 C++ 上的分段错误
- 为什么我的布尔变量会更改(C )
- 允许使用布尔变量和值的功能
- 非标准语法;使用"&"创建指向成员的指针。访问布尔变量
- 监视全局变量/布尔表达式的更改