与位域相邻的variables是否会被破坏?

我面临的问题非常类似于Linux内核社区所描述的 – 由Bit-Field背叛

问题的实质是GCC发布64位读取访问甚至访问1位的位域。 这会导致在相邻字段中读取的意外副作用,这些字段可以在程序的其他地方修改。 当修改的位域值被写回时,相邻variables的旧值也被写回,从而失去了其他线程对其进行的任何修改。

我的问题稍有不同。 我有一个类/结构像这样 –

class Group { uint8 adjVariable; volatile bool flag1: 1; volatile bool flag2: 1; // so on... volatile bool flag10: 1; }; 

这些variables被访问的方式是 –

 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!! } 

在我们怀疑使用GCC的“bug”之前,我确认了在其他地方没有使用Group_lock()情况下访问Group_lock() 。 尽我所能,我无法看到代码中发生这种情况的任何地方。

现在,由于编译器对位域进行64位读取并且它们是易失性的,所以如果它作为该读取的一部分发出读取到adjVariable并且adjVariable的显式ZERO分配仍然在caching中并且因此我们读取旧值12作为adjVariable ? 这个新读取的值会覆盖显式的设定值吗? 因此,我们绊倒assert ? 如果是这样,我如何validation呢?

在这篇文章中,他们正在讨论丢失在其他线程中完成的相邻variables的更新,但是在我的问题中,我怀疑由于从内存读取而在同一个线程中完成的adjVariable更新失败。 这可能吗?

我们正在使用一个古老的g ++编译器,这个编译器在同样较旧的Fedora 12版虚拟机上只符合C ++ 98标准。 此外,我们只运行了一个代码库,运行了6个月

如果adjVariable不是从任何其他并发线程访问的,那么它在断言点几乎保证为0。

虽然所有的bool是一个单一的内存位置,确实可以产生一些奇怪的行为之间, adjVariable是一个单独的内存位置,编译器必须确保所有的加载和存储看起来发生在定义良好的顺序到源代码。

如果编译器对位字段进行64位操作,则它必须通过将位字段对齐到8字节来保护相邻的存储单元(例如,在adjVariableflag1之间应该有7字节的填充)。 尽管这里我没有看到64位读取是否可以纠正正确性。

虽然内存位置的概念只适用于C ++ 11及更高版本,但逻辑仍然适用于C ++ 98:在assert中, adjVariable不能为零的唯一方法应该是让另一个线程写入adjVariable