Pav*_*ath 5 c++ linux multithreading gcc
我面临的问题与Linux内核社区所描述的问题非常相似- 由位域背叛
问题的实质在于,GCC发出64位读取访问以访问偶数1位位域。这会导致读取相邻字段的意外副作用,而该副作用可在程序的其他位置进行修改。当回写修改后的位域值时,相邻变量的旧值也会被回写,从而丢失其他线程对其所做的任何修改。
我的问题略有不同。我有这样的课程/结构-
class Group {
uint8 adjVariable;
volatile bool flag1: 1;
volatile bool flag2: 1;
// so on...
volatile bool flag10: 1;
};
Run Code Online (Sandbox Code Playgroud)
访问这些变量的方式是-
Group::fun() {
Group_Scoped_lock();
// adjVariable was 12 here.
if ( adjVariable > 0 ) {
adjVariable = 0; // <------- EXPLICIT ZERO ASSIGNMENT
}
// some code that doesn't affect adjVariable
bool1 = false;
bool2 = false;
bool3 = false;
assert( adjVariable == 0 ); // <---- This assert is tripping stating that adjVariable is 12!!
}
Run Code Online (Sandbox Code Playgroud)
在我们怀疑与GCC发生“错误”之前,我验证了是否adjVariable在没有Group_lock()其他地方的情况下进行了访问。尽我所能,我看不到代码中发生这种情况的任何地方。
现在,由于编译器对位域发出64位读取并且它们是易失性的,如果它adjVariable作为该读取的一部分发出了to 的读取,并且显式的ZERO分配adjVariable仍在高速缓存中,因此我们为12读取了较早的值,该adjVariable怎么办?并且这个新读取的值会覆盖显式设置的值吗?因此,我们跳闸了assert?如果是这样,我该如何验证?
在本文中,他们讨论的是丢失对其他线程中完成的相邻变量的更新,但是在我的问题中,我怀疑由于内存中的读取而导致adjVariable对同一线程中完成的更新的丢失。这可能吗?
我们正在使用古老的g ++编译器,该编译器在同样旧的Fedora版本12虚拟机上仅符合C ++ 98。另外,只有运行6个月的代码库才遇到此问题
如果adjVariable没有从任何其他并发线程访问,那么在断言点几乎可以保证为 0。
虽然所有的bools 都是单个内存位置,并且确实可以在它们之间产生一些奇怪的行为,但adjVariable它是一个单独的内存位置,编译器必须确保对其进行的所有加载和存储似乎都按照符合以下规则的明确定义的顺序进行:源代码。
如果编译器对位字段发出 64 位写入adjVariable,则它必须通过将位字段与 8 字节对齐来保护相邻的内存位置(例如和之间应该有 7 字节填充flag1)。不过,我不明白 64 位读取会如何影响正确性。
虽然内存位置的概念仅适用于 C++11 及更高版本,但逻辑仍然适用于 C++98:adjVariable断言中不为零的唯一方法应该是让另一个线程写入adjVariable.
| 归档时间: |
|
| 查看次数: |
155 次 |
| 最近记录: |