如果两个线程同时访问同一个 bool 变量会发生什么?
我有一个跨平台 C++ 程序,其中使用 boost 库创建异步计时器。
我有一个全局变量:
bool receivedInput = false;
一个线程等待并处理输入
string argStr;
while (1)
{
getline(cin, argStr);
processArguments(argStr);
receivedInput = true;
}
另一个线程运行一个计时器,其中每 10 秒调用一次回调。在该回调中,我检查是否收到消息,
if (receivedInput)
{
//set up timer to fire again in 10 seconds
receivedInput = false;
}
else
exit(1);
那么这安全吗?对于线程 2 中的读取,我认为这并不重要,因为条件将评估为 true 或 false。但我不确定如果两个线程尝试同时设置 receiveInput 会发生什么。我还将计时器设置为比我预期接收输入的时间长 3 倍,这样我就不担心竞争条件。
编辑: 为了解决这个问题,我在设置receivedInput时使用了boost::unique_lock,在读取receivedInput时使用了boost::shared_lock。我使用了此处中的示例
I have a cross platform c++ program where I'm using the boost libraries to create an asynchronous timer.
I have a global variable:
bool receivedInput = false;
One thread waits for and processes input
string argStr;
while (1)
{
getline(cin, argStr);
processArguments(argStr);
receivedInput = true;
}
The other thread runs a timer where a callback gets called every 10 seconds. In that callback, I check to see if I've received a message
if (receivedInput)
{
//set up timer to fire again in 10 seconds
receivedInput = false;
}
else
exit(1);
So is this safe? For the read in thread 2, I think it wouldn't matter since the condition will evaluate to either true or false. But I'm unsure what would happen if both threads try to set receivedInput at the same time. I also made my timer 3x longer than the period I expect to receive input so I'm not worried about a race condition.
Edit:
To solve this I used boost::unique_lock when I set receivedInput and boost::shared_lock when I read receivedInput. I used an example from here
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这从根本上来说是不安全的。线程 1 将
true
写入receivedInput
后,不保证线程 2 会看到新值。例如,编译器可能会优化您的代码,在用作 if 条件时对receivedInput
的值做出某些假设或将其缓存在寄存器中,因此不能保证主内存会实际上是在评估 if 条件时读取的。此外,编译器和 CPU 都可能会更改读写顺序以进行优化,例如可以在getLine()
之前将true
写入receivedInput
和processArguments()
。此外,依赖计时进行同步是一个非常糟糕的主意,因为通常您无法保证每个线程在给定时间间隔内获得的 CPU 时间量,或者是否会在给定时间间隔内进行调度。
一个常见的错误是认为使
receivedInput
volatile
可能会有所帮助。事实上,易失性保证值实际上被读/写到主存储器(而不是例如缓存在寄存器中),并且变量的读和写是相对于彼此排序的。但是,它不保证 volatile 变量的读取和写入相对于其他指令是有序的。您需要内存屏障或适当的同步机制才能使其按您的预期工作。
This is fundamentally unsafe. After thread 1 has written
true
toreceivedInput
it isn't guaranteed that thread 2 will see the new value. For example, the compiler may optimize your code making certain assumptions about the value ofreceivedInput
at the time it is used as the if condition or caching it in a register, so you are not guaranteed that main memory will actually be read at the time the if condition is evaluated. Also, both compiler and CPU may change the order of reads and writes for optimization, for exampletrue
may be written toreceivedInput
beforegetLine()
andprocessArguments()
.Moreover, relying on timing for synchronization is a very bad idea since often you have no guarantees as to the amount of CPU time each thread will get in a given time interval or whether it will be scheduled in a given time interval at all.
A common mistake is to think that making
receivedInput
volatile
may help here. In fact,volatile
guarantees that values are actually read/written to the main memory (instead of for example being cached in a register) and that reads and writes of the variable are ordered with respect to each other. However, it does not guarantee that the reads and writes of thevolatile
variable are ordered with respect to other instructions.You need memory barriers or a proper synchronization mechanism for this to work as you expect.
您必须检查您的线程标准。假设我们讨论的是 POSIX 线程,这是一种明确未定义的行为——一个对象可能无法被一个线程访问,而另一个线程正在或可能正在修改它。 任何事情都可能发生。
You would have to check your threading standard. Assuming we're talking about POSIX threads, this is explicitly undefined behavior -- an object may not be accessed by one thread while another thread is or might be modifying it. Anything can happen.
如果你的线程使用receivedInput的值来控制独立的代码块,而不是相互同步,有一个简单的解决方案:
在receivedInput之前添加“易失性”,这样编译器就不会进行优化,防止线程共享收到输入。
If your threads use the value of receivedInput to control independent code blocks, but not to synchronize with each other, there is one simple solution:
add "volatile" before receivedInput, so the compiler will not do the optimization preventing the threads share the value of receivedInput.