螺纹安全和钻头领域
Thread safety and bit-field
我知道位字段依赖于编译器,但我还没有找到关于最新g++和Visual C++2010的位字段线程安全的文档。
对位字段成员的操作是原子操作吗?
"线程安全"在编程中是一个非常重载的术语。
如果您的意思是原子访问位字段,答案是否定的(至少在我所知道的所有处理器上是这样)。您可以原子访问32位机器上的32位内存位置,但这只意味着您将读取或写入整个32位值。这并不意味着另一个线程不会做同样的事情。如果您希望停止,则可能需要同步。
如果您的意思是同步对位字段的访问,那么答案也是否定的,除非您将访问封装在更高级别的同步原语中(通常基于原子操作)。
简而言之,编译器不提供对位字段的原子或同步访问,而无需您额外的工作。
这有帮助吗?
编辑:Dan Grossman博士有两堂关于原子性和同步的精彩讲座,我在UOregon的CS部门页面上找到了。
在写入位字段时,可能会有一个时间窗口,在这个时间窗口中,另一个线程试图访问(读取或写入)同一结构中的任何(相同或不同)位字段都会导致"未定义行为",这意味着任何事情都可能发生。在读取位字段时,可能会有一个时间窗口,当另一个线程试图在同一结构中写入任何位字段时都会导致"未定义行为"。
如果您实际上不能为有问题的位字段使用单独的变量,则可以将多个位字段存储在一个整数中,并通过在位字段结构和32位整数之间创建并集,然后使用CompareExchange序列进行原子更新:
- 将位字段的值读取为Int32。
- 将其转换为位字段结构
- 更新结构
- 将结构转换回Int32。
- 仅当变量仍保留(1)中读取的值时,才使用CompareExchange用新值覆盖该变量;如果该值已更改,请从步骤(1)重新开始。
为了使这种方法能很好地工作,步骤2-4必须很快。它们花费的时间越长,步骤5中的CompareExchange失败的可能性就越大,因此在CompareExchange成功之前,必须重新执行步骤2-4的次数就越多。
如果您想以线程安全的方式更新位字段,您需要将位字段拆分为单独的标志,并使用常规的int
来存储它们。访问单独的机器字是线程安全的(尽管您需要考虑多处理器系统上的优化和缓存一致性)。
请参阅Windows互锁函数
另请参阅此相关SO问题
只需简单使用原子。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++也有一些类似原子的东西。AddInt32
- 从不同线程使用int64的不同字节安全吗
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 虚拟决赛作为安全
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何将元素添加到数组的线程安全函数?
- C++中的线程安全删除
- 通过网络、跨平台传递std::变体是否安全
- 在std::thread中,joinable()然后join()线程安全吗
- 使用std::istream::peek()总是安全的吗
- 从值小于256的uint16到uint8的Endian安全转换
- 在c++队列中使用pop和visit实现线程安全
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 以线程安全的方式调用"QQuickPaintedItem::updateImage(const QImage&image)"(no QThread)
- 全局变量 多读取器 一个写入器多线程安全?
- 安全到标准:移动会员?
- AcquireCredentialsHandleA() 返回 PFX 文件的0x8009030e(安全包中没有可用的凭据
- 共享队列的线程安全
- boost::文件系统::recursive_directory_iterator多线程安全
- 跨 DLL 边界访问虚拟方法是否安全/可能?
- C++动态安全 2D 交错阵列