在生成访问共享资源的子线程之前,是否应该由父线程锁定对共享资源的访问?

时间:2010-02-10 08:50:42

标签: multithreading locking thread-safety multicore shared-memory

如果我有以下的伪代码:

sharedVariable = somevalue;
CreateThread(threadWhichUsesSharedVariable);

理论上多核CPU是否可以在threadWhichUsesSharedVariable()中执行代码,该代码在父线程写入之前读取sharedVariable的值?为了完全理论上避免即使是竞争条件的远程可能性,代码应该是这样的:

sharedVariableMutex.lock();
sharedVariable = somevalue;
sharedVariableMutex.unlock();
CreateThread(threadWhichUsesSharedVariable);

基本上我想知道线程的产生是否在那时明确地线性化了CPU,并且保证这样做。

我知道线程创建的开销可能需要足够的时间才能在实践中无关紧要,但我的完美主义者却害怕理论上的竞争条件。在极端条件下,某些线程或核心可能会严重滞后而其他线程或核心可能会快速有效地运行,我可以想象,除非存在锁定,否则执行(或内存访问)的顺序可能会被逆转。< / p>

2 个答案:

答案 0 :(得分:2)

我会说你的伪代码在任何正常运行时都是安全的 多处理器系统。 C ++编译器无法生成调用 CreateThread()之前的sharedVariable已收到正确的值 除非能证明这样做是安全的。你有保证 您的单线程代码完全等效地执行 非重新排序的线性执行路径。任何“时间扭曲”的系统 变量赋值之前的线程创建严重破坏。

我不认为声明sharedVariable挥发性做任何事情 在这种情况下很有用。

答案 1 :(得分:1)

鉴于您的示例,如果您使用的是Java,则答案为“否”。在Java中,线程无法在赋值操作完成之前生成并读取您的值。 在其他一些语言中,这可能是另一回事。

“多个线程之间共享的变量(例如,对象的实例变量)具有Java语言规范保证的原子赋值,用于除long和double之外的所有数据类型...如果方法仅包含单个变量访问或者赋值,没有必要为了线程安全而使它同步,并且没有必要为了性能而不这样做。“ reference

如果doublelong被声明为volatile,那么您也可以保证分配是原子操作。

更新: 您的示例将在C ++中工作,就像它在Java中一样。从理论上讲,线程生成无法在赋值之前开始或完成,即使是乱序执行也是如此。

请注意,您的示例非常具体,在任何其他情况下,建议您确保正确保护共享资源。新的C ++标准出现了很多原子,所以你可以将你的变量声明为原子,并且所有线程都可以看到赋值操作,而不需要锁定。 CAS(比较和设置)是您的下一个最佳选择。