例如,有这样一段代码:
void obj::foo() {
... // some operations
std::lock_guard lock{mut_};
... // some operations and initialization ariables
lock.unlock();
... // other operations
}
如您所见,关键部分位于函数的中间,并用互斥锁隔离。但是,我在某处读到,如果它们不相互依赖,编译器可以自行决定对操作顺序进行改组,所以我想澄清一下:是否保证初始化lock和调用之间的所有内容都lock.unlock()将受到互斥锁的保护?或者编译器可以决定这些调用之间的某些操作可以在锁之外的其他地方执行?
TL;DR:如果他能证明没有人会注意到,他可以重新安排。
编译器有权随意更改操作,它们的顺序,丢弃任何操作并引入新的操作,只要从单线程代码的角度来看最终结果是相同的。此权限称为as-if 规则,允许编译器生成更优化的代码*。
各种同步结构(例如互斥锁)限制了编译器的自由度**。在互斥操作的边界(即锁定或解锁所在的点)处的外部可见效果(例如,线程之间共享的变量的状态)应该与没有优化时相同。
其他更改仍然是可能的。例如,如果一个变量是本地的,并且编译器发现它对其他线程的合法方法不可见,它仍然可以对它做任何想做的事情,只要结果相同。
示例:在此代码中
clang 编译器在释放互斥锁后将值为 2 的工作转移到作用域,并且值 1 的赋值与变量一起被完全丢弃
i。我们看到互斥锁不保护变量,而是共享状态。
* 好吧,处理器也有权使用这些技巧,这是一个单独的问题。
**并强制它在代码中插入限制处理器自由的指令。