2011-12-07 45 views
4

我有一个跨平台的C++程序,我使用boost库创建一个异步计时器。
我有一个全局变量:如果两个线程同时访问相同的bool变量会发生什么情况?

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中的读取,我认为这并不重要,因为条件将评估为真或假。但我不确定如果两个线程尝试同时设置receivedInput会发生什么情况。我也让我的计时器比我期望接收输入的时间长3倍,所以我不担心竞赛状况。

编辑: 为了解决这个问题,我使用了boost :: unique_lock,当我设置receivedInput和boost :: shared_lock时,当我读receivedInput。我用here的一个例子

+2

¤如果你想知道它是否安全,那么它不是。不管技术上是否安全,在线程的情况下,如果你不了解它,那么即使它是完美的开始,它也会在短时间内发现错误。因为它发生的代码在技术上是不安全的,但实际上是安全的。例如,在技术上,当“输入”线程处理七行时,“检查​​”线程可能在“if”处暂停。但在实践中,这不会发生,但是像Bad Things™*这样的代码将会发生。 :-)干杯&hth。 –

回答

5

这基本上是不安全的。线程1写入truereceivedInput后,不保证线程2将看到新值。例如,编译器可能会优化您的代码,以便在它被用作if条件或将其缓存在寄存器中时对receivedInput的值作出某些假设,因此您不能保证主存储器在实际读取时如果条件被评估。此外,编译器和CPU都可能会改变读取和写入的顺序以进行优化,例如true可能会在getLine()processArguments()之前写入receivedInput。另外,依赖于同步的时机是一个非常糟糕的想法,因为通常你不能保证每个线程在给定的时间间隔内将获得的CPU时间量,或者它是否将在给定的时间间隔所有。

一个常见的错误是认为制作receivedInputvolatile可能会有所帮助。实际上,volatile保证值实际上被读取/写入主存储器(而不是例如被缓存在寄存器中),并且变量的读取和写入相对于彼此排序。但是,它并不保证volatile变量的读取和写入相对于其他指令被排序。

您需要内存屏障或适当的同步机制才能按预期工作。

1

你将不得不检查你的线程标准。假设我们正在讨论POSIX线程,这是明确未定义的行为 - 一个线程可能无法访问某个对象,而另一个线程正在或可能正在修改它。 任何东西都可能发生。

+2

截至2011年9月,您的线程标准可能是C++标准! –

+0

@SteveJessop我一直在忘记! –

0

如果你的线程使用receivedInput的值来控制独立的代码块,而不是相互同步,有一个简单的解决方案:

添加“挥发性” receivedInput之前,所以编译器不会做优化阻止线程共享receivedInput的值。

+2

我不想-1因为你是新的,我不想让你离开,但我不想要“volatile”对多线程传播有用的误解。它没有用,'volatile'与线程无关,也不是同步的一种方法。 – GManNickG

+0

感谢您的评论。是的,我在这里犯了一个错误,两个线程为同一个变量赋值。这里需要同步。但是volatile与多线程无关。 “一般来说,volatile关键字旨在防止编译器对代码中的任何优化应用,这些代码假设变量的值无法自行更改(我从wikipedia重新检查它):) – xiesusu

+1

但请注意,多线程不仅限于对变量禁用优化。 – GManNickG

相关问题