是否使用 Guard 类免受编译器优化和 CPU 重新排序的影响
Is use of a Guard class safe from compiler optimization and cpu reordering?
我已经看到这种模式在我正在使用的一些代码中弹出,我理解它的意图是什么,我理解为什么人们喜欢它,但它有一些不适合我的东西。模式是警卫类。这个想法是你有一些关键部分,你之前创建了一个 Guard g(somemutex) 的实例,它获取(或尝试获取)somemutex,然后当 g 超出范围时,它会释放 g 析构函数中的互斥锁。这真的很酷,因为它可以让您在函数中的任何位置输入返回,而无需担心记住释放锁。
我关心的是优化。如果关键部分中的项被标记为易失性,则编译器无法在构造函数的函数调用中移动它们。类似地,如果该项在编译单元之外是可复制的(即,如果一个类具有公共成员,则该成员可以在定义它的单元之外合理地更改)。 编译器不能假定它可以移动该项。但是,如果该项是类的私有项并且未声明易失性,则编译器没有理由认为编译单元之外的任何代码都会影响它,也没有理由相信它必须出现在 Guard 构造函数之前或之后。例如:
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是一个范围未知的变量。在这种情况下,范围是已知的。变量是类的私有成员。在这种情况下,修改它的唯一方法是调用类的公共函数。guard类不可能有指向调用函数的指针或引用,因为我们没有将其传递给构造函数,这意味着编译器可以肯定地知道创建g不能修改变量。事实上,它不会修改它。
由于notVolatilePrivateVar
不是函数foo
的本地变量,因此必须将其视为"全局"变量(可能有另一个指针实例与可以访问notVolatilePrivateVar
实体具有相同值this
。
换句话说,只要编译器不知道mutex
的确切实现,或者mutex
的实现在实现中有一个"编译器屏障"[如果它是一个内联函数,它应该有,否则它对这种事情是不安全的]。
这个点之后",它的目的正是为了防止互斥体实现在它们要保护的简单变量之间"泄漏"。
换句话说,只要mutex
设计正确,编译器就不能"破坏"Guard
的承诺。
- 二叉排序树无法编译
- 仅使用绝对值对数组进行排序,并在C++中显示实际值
- C++选择排序算法中的逻辑错误
- 使用C++程序合并排序没有得到正确的输出
- 计算排序向量的向量中唯一值的计数
- 排序算法c++
- 使用2个键的cpp-stl::优先级队列排序不正确
- 将结构向量排序为子组
- 在c++中尝试对对象数组进行排序时,出现std:bad_alloc错误
- 数组将排序排序为降序而不是升序
- 如何按姓氏排序并打印新数组
- 将一个数组的每个元素乘以另一个数组的每个元素,并对新的非常大的数组进行排序
- 合并排序 - 返回新数组,而不是将合并的数组复制到输入数组
- 如何对骰子进行排序并创建每个数组中具有相等骰子的新数组,Yahtzee,C++
- 与排序相关的算法(将每个项目替换为排序排序中的索引)
- 如何将未排序数组的排序索引放入新数组中
- "std::"具有排序/排序、存在测试和头/尾访问的数据结构?
- 创建没有重复项的新排序向量
- 使用快速排序排序不会给出排序的数组
- 读取文本行,对它们进行排序并将它们写入新的文本文件