如果我不使用互斥锁,源代码有什么问题吗?
bool bStop = false;
void thread1_fun()
{
while (!bStop)
{
doSomething();
}
}
void thread2_fun()
{
bStop = true;
}
答案 0 :(得分:14)
在另一个线程访问该对象时,写入一个线程中的对象是未定义的行为。
除非您特别告知编译器应该有一个围栅,例如使用std::atomic
,std::mutex
等,否则所有赌注均已关闭。
编译器有权重新编写代码:
bool bStop = false;
void thread1_fun()
{
const bool stopped = bStop;
// compiler reasons: "because there is no fence, the variable clearly cannot
// have changed to true, since no-other thread will modify it, since
// to modify it without a fence would be UB."
while (!stopped)
{
doSomething();
}
}
void thread2_fun()
{
// this happens in my thread's view of the world,
// but no other thread need see it.
bStop = true;
}
答案 1 :(得分:9)
如果我不使用互斥锁,源代码是否有任何问题?
是的,您有竞争条件,这会导致未定义的行为。
您需要使用std::atomic<bool>
或使用bStop
等同步原语保护对std::mutex
的写入/读取。
与(遗憾的)共同信念相反,将bStop
标记为volatile
不在此解决任何问题。 volatile
限定符与线程安全无关。
答案 2 :(得分:1)
在一个线程中写入变量并在另一个线程中读取该变量的值是数据竞争。具有数据竞争的程序具有未定义的行为;这意味着C ++标准没有告诉你该程序将做什么。您可以通过使变量原子或使用各种同步来避免数据竞争,最常见的是std::mutex
和std::condition_variable
。< / p>
您可能能够通过分析您正在编译的代码的详细信息,使编译器如何从该源生成目标代码的详细信息,使程序在没有同步的情况下可靠地“工作”代码,以及硬件如何处理生成的对象代码的详细信息。然后,如果你改变这三个中的任何一个,你必须重新进行分析,因为这些改变可能不再“起作用”了。当然,如果你这样做,那么你就会被高级语言所拯救的所有细节所困扰。除非在极少数情况下,这根本不值得努力。正确使用该语言。