0

我已经在我正在使用的一些代码中看到了这种模式,我理解它的意图是什么,我理解为什么人们喜欢它,但它有一些不适合我的地方。模式是 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 不能修改变量。实际上它不会修改它。

4

1 回答 1

0

由于notVolatilePrivateVar它不是函数的本地变量foo,因此必须将其视为“全局”变量(可能存在与this可以访问notVolatilePrivateVar实体具有相同值的指针的另一个实例。

换句话说,只要编译器不知道 的确切实现mutex,或者 的实现在实现中mutex有一个“编译器障碍”[如果它是一个内联函数它应该有,否则它不会安全这种事情]。

“编译器屏障”是一种结构,它告诉编译器“你不能从这个点之后移动东西,使它在这个点之前,或者在这个点之前的东西移动到这个点之后”,它的目的正是为了防止示例互斥锁实现不会“泄漏”它们旨在保护的简单变量。

换句话说,Guard只要mutex设计正确,编译器就不能“破坏” 的承诺。

于 2013-09-20T21:47:18.633 回答