线程安全和位域

时间:2011-05-31 19:36:50

标签: c++ c thread-safety bit-fields

我知道位字段依赖于编译器,但是我没有找到有关最新g ++和Visual C ++ 2010的位字段安全性的文档。

位字段成员的操作是否是原子的?

5 个答案:

答案 0 :(得分:5)

不幸的是,“线程安全”在编程中是一个非常重载的术语。

如果你的意思是原子访问位字段,答案是否定的(至少在我所知的所有处理器上)。您对32位机器上的32位内存位置有原子访问权限,但这只意味着您将读取或写入整个32位值。这并不意味着另一个线程不会做同样的事情。如果你想停下来,你可能想要同步。

如果您的意思是同步访问位字段,那么答案也是否定的,除非您将访问权限包含在更高级别的同步原语中(通常基于原子操作构建)。

简而言之,编译器不会提供原子同步访问位字段,而无需您做额外的工作。

这有帮助吗?

修改Dr. Dan Grossman has two nice lectures on atomicity and synchronization I found on UOregon's CS department page

答案 1 :(得分:2)

当写入位字段时,可能存在一个时间窗口,其中另一个线程在同一结构中访问(读取或写入)任何(相同或不同)位字段的任何尝试都将导致未定义的行为,意味着什么都可以发生当读取位字段时,可能存在时间窗口,当另一个线程在同一结构中写入任何位字段的任何尝试都将导致未定义的行为。

如果你实际上不能对所讨论的位字段使用单独的变量,你可以在一个整数中存储多个位字段,并通过在位字段结构和32位之间创建一个联合来原子地更新它们整数,然后使用CompareExchange序列:

  1. 将Intfield的值读取为Int32。
  2. 将其转换为位域结构
  3. 更新结构
  4. 将结构转换回Int32。
  5. 只有当变量仍然保存在(1)中读取的值时,才使用CompareExchange用新值覆盖变量;如果值已更改,请从步骤(1)重新开始。

要使这种方法运作良好,步骤2-4必须快速。它们花费的时间越长,步骤5中的CompareExchange失败的可能性就越大,因此在CompareExchange成功之前,必须重新执行步骤2-4的次数。

答案 2 :(得分:1)

如果要以线程安全的方式更新位域,则需要将位字段拆分为单独的标志,并使用常规int来存储它们。访问单独的机器字是线程安全的(尽管您需要考虑多处理器系统上的优化和缓存一致性。)

答案 3 :(得分:1)

答案 4 :(得分:0)

只需简单地使用atomic.AddInt32 例如:

atomic.AddInt32(&intval, 1 << 0)      //set the first bit
atomic.AddInt32(&intval, 1 << 1) //set the second bit
atomic.AddInt32(&intval, -(1 << 1 + 1 << 0)) //clear the first and second bit

代码在Go中,我认为c ++也有一些像atomic.AddInt32

这样的东西