我已经在我正在使用的一些代码中看到了这种模式,我理解它的意图是什么,我理解为什么人们喜欢它,但它有一些不适合我的地方。模式是 Guard 类。这个想法是你有一些关键部分,你通过创建一个 Guard g(somemutex) 的实例来获取(或尝试获取)somemutex,然后当 g 超出范围时,它会在 g 的析构函数中释放互斥锁。这真的很酷,因为它可以让您在函数中的任何位置输入返回,而无需担心记住释放锁。
我关心的是优化。如果临界区中的项目被标记为易失性,则编译器无法将它们移动到构造函数的函数调用中。类似地,如果项目在编译单元之外是可见的(即,如果一个类有一个公共成员,那么该成员可以在定义它的单元之外合理地更改。)编译器不能假设它可以移动该项目。但是,如果该项目是类的私有且未声明为 volatile,则编译器没有理由认为编译单元之外的任何代码都会影响它,也没有理由相信它必须出现在构造函数之前或之后警卫队。例如:
void foo(int i){
Guard<mutex> g(mymutex);
notVolatilePrivateVar = i;
}
//gets compiled to look like...
void foo(int i){
notVolatilePrivateVar = i;
Guard<mutex> g(mymutex);
}
现在我不是在问它是否可能发生,我是在问是否有保证不会发生。
同样,对于多个问题 cpu 的此类事情可能会发生,但我认为它更不可能发生,因为 cpu 对变量或函数是什么一无所知。
编辑:我以前读过这个问题编译器围绕互斥边界重新排序? 但它并没有完全解决我的疑虑。在那种情况下,_field 是一个范围未知的变量。在这种情况下,范围是已知的。该变量是该类的私有成员。在这种情况下,修改它的唯一方法是调用类的公共函数。守护类不可能有一个指向调用函数的指针或引用,因为我们没有将它传递给构造函数,这意味着编译器可以确定地知道创建 g 不能修改变量。实际上它不会修改它。