我是一个静态的64位整数变量"仅由一个线程更新。 所有其他线程只能从中读取。
出于安全原因,我是否应该使用原子操作保护此变量(例如" __ sync_add_and_fetch")?
或者可以直接从(resp。)中读取(resp。)吗?
我仍然感到困惑,因为我没有找到明确的答案。我不知道我是否要保护它:
谢谢你。
答案 0 :(得分:-1)
作为一个简单的答案,我建议你只有在写信时才能保护它(不能直接写)。
虽然您知道如果您正在做类似的事情并且线程未同步,您可能每次都会得到不同的结果。
PS。我希望这是一个评论,但我的代表太低了
答案 1 :(得分:-1)
通常,读取和写入存储位置的原子性是相同的。
也就是说,如果一个位置不能以原子方式写入,也不能以原子方式读取,反之亦然。
如果需要特殊的原子写入,除非读取也是原子的,否则使用它是没有意义的。
例如,假设使用普通读取来读取64位位置,这需要例如两次32位访问。假设写入介于这两个访问之间。读取将从新值中获取第二个32位,并将其与过时的前32位组合。写入不能介于读取的两半之间的唯一方法是读取是否为原子。原子读取知道如何正确地与原子写入交互以防止这种情况。
您可能会对此规则的“例外”感到困惑。在某些系统中,您可能会看到原子更新,例如增量,与普通读取混合。这是基于读写事实上是原子的假设;特殊原子增量仅用于使读取/修改/写入周期从并发写入器的角度看起来是不可分割的:如果N个写入器在大约相同的时间执行此增量,则确保该位置增加N.
有时您可能会看到使用普通读取的正确优化,即使基础数据类型未以原子方式访问也是如此。在这种情况下,算法并不关心它是否读取“半烘焙”值。
例如,为了简单地监视内存位置以检测更改,您不需要原子读取。检测更改不需要检索正确的值。例如,0x00000000更新为0x00010001,但非原子读取观察到中间值0x00010000,这仍然足以检测到位置已更改。
如果你必须确保读者永远不会看到一个半生不熟的值,那么使用原子读写。
还有其他问题,例如订购。假设一个编写器更新了两个位置,A和B.在某些计算系统中,读者可以在A之前观察B的更新。除了任何原子之外,还必须使用特殊的“屏障”或“栅栏”指令。更新说明。
在更高级别的语言中,这些障碍的API可能会被构建到某些原子操作的语义中,因此您可能最终只是为了这些障碍而使用原子指令,即使该数据是原子的
答案 2 :(得分:-1)
是。你需要一个读写器锁。这正是他们所做的。写作时的障碍和读者可以阅读的其他内容
如果你正在使用提升,我相信它是boost::shared_mutex
C ++当前不支持读写器锁,但您可以自己实现它们。
有关读写器锁的更多信息,请查看here
答案 3 :(得分:-3)
如果目标体系结构支持64位值的原子读/写,则根本不需要保护:编译器将自动使用相应的指令。最好使用'volatile'在这种情况下,修饰符阻止编译器在单个读取器中读取值两次。
否则,您应该使用某种关键部分围绕写入更新程序线程并读入读取器线程。它可能是互斥,读写锁,seq-lock等。
似乎纯粹的" C"没有预先确定的检测方法,在给定的机器上是否支持64位值的原子读/写。但是有很多方法可以检测,无论机器本身是64位还是不是。您可以安全地假设64位机器支持64位原子读/写。