在哪种情况下编译器可以按照自己的意愿重新排序指令?
例如,如果涉及同步原语(如互斥锁),可以重新排序它们,如下例所示:
unlock
在某些条件下,此代码可以打印1而不是0吗?
在这样的互斥锁上调用int some_global_variable = 0;
// Thread 1
mutex.lock();
some_global_variable = 1;
mutex.unlock();
// Thread 2
mutex.lock();
std::cout << some_global_variable << std::endl;
mutex.unlock();
后,是否会实际修改任何共享变量,这样可以保证其他线程会看到这些变量的更新值,而不是可能缓存的变量值?
它是否适用于所有众所周知的同步原语,如关键部分,互斥体等?
是否还保证以下代码(假设线程1将在线程2之前获取指定的互斥锁)将始终打印1而不是某些缓存值(例如,0):
join
如果是这样,为什么?它在哪里说明了?
答案 0 :(得分:2)
不,它不能。互斥体的一个显着特征是代码重新排序不会跨越互斥量获取或释放。
另一方面,关键部分不是Posix模型中的同步原语(C ++线程主要基于该原型)。相反,它是一个逻辑术语,意味着必须受到保护的代码片段。
修改强>
回答第二个问题。
是的,保证如果线程1首先获取互斥锁,则打印的值将为1.此显式保证的原因是互斥锁低级代码与此代码的硬件实现的组合。虽然没有说明,但我假设两段代码属于两个不同的功能(为简单起见)。请注意,在这种情况下,无论使用互斥锁,都不会使用编译器优化 - 有两个独立的函数,编译器优化是函数的本地优化。
在互斥级别上,互斥锁的任何实现都包含直接或间接指令,以便在获取互斥锁之前和之后放置内存栅栏。 Thos instrucion将指示hardwre刷新所有缓存,因此不会使用缓存值。
答案 1 :(得分:2)
在哪种情况下编译器可以按照自己的意愿重新排序指令?
如果编译器能够证明重新排序没有在同一个线程中可观察到的副作用。
在某些条件下,此代码可以打印1而不是0吗?
没有
当然不是由于编译器重新排序指令,因为x
在同一个线程中被读取和写入并且更改顺序以便打印1显然是一个可观察到的副作用。
也不是因为另一个线程写入x
,因为它是一个自动变量而你在任何时候都没有它的地址,因此很容易证明它不能与其他线程共享。 / p>