我有一个应用程序,其中多个线程访问并写入1个字(16位)的共享内存。
我可以期望处理器在原子操作中从/向内存读取和写入字吗?所以我不需要共享内存/变量的互斥保护?
目标是运行VxWorks的嵌入式设备。
编辑:只有一个CPU而且它是旧的(> 7年) - 我不完全确定架构和型号,但我对#34的一般方式也更感兴趣;最" CPU会起作用。如果它是一个16位CPU,那么在大多数情况下,是否可以预期它会在一次操作中读/写一个16位变量?或者我应该总是在任何情况下使用互斥保护?让我们说我不关心可移植性,我们谈论C ++ 98。答案 0 :(得分:2)
问题不在于访问的原子性(除非使用8位MC,否则通常可以假设),但缺少的同步会导致未定义的行为。 如果要编写可移植代码,请改用atomics。如果你想为你的特定平台实现最大性能,请仔细阅读你的操作系统和编译器的文档,看看它们为多线程程序提供了哪些额外的机制或保证(但我真的怀疑你会找到比std更有效的东西::原子能给你足够的保证。)
答案 1 :(得分:2)
所有处理器将以原子方式读取和写入对齐的机器字,因为如果另一个处理器读取,您将不会获得旧值的一半位和新值的一半位。
为了实现良好的速度,现代处理器不会将读取 - 修改 - 写入操作同步到特定位置,除非您实际要求它 - 因为几乎所有读取和写入都会转到“非共享”位置。
所以,如果值是,例如,我们遇到特定条件的次数的计数器,或者其他一些“如果我们读/写旧值,它会出错”的情况,那么你需要确保两个处理器不同时更新该值。这通常可以通过atomic
指令(或其他形式的atomic
更新)来完成 - 这将确保一个且只有一个处理器在任何给定时间触及该值,并确保所有其他处理器处理器不要持有他们认为准确的值的副本,并且在另一个刚刚进行更新时保持最新。请参阅C ++ 11 std::atomic
函数集。
注意原子地读取或写入机器词的值并原子地执行整个更新之间的区别。
答案 2 :(得分:2)
我能指望处理器在原子操作中从/向内存读取和写入字吗?
是
所以我不需要共享内存/变量的互斥保护?
没有。考虑:
++i;
即使读取和写入都是原子的,同时执行此操作的两个线程可以每次读取,每次递增,然后每次写入,从而只需要一个增量,其中需要两个。
答案 3 :(得分:1)
我能指望处理器在原子操作中从/向内存读取和写入字吗?
是的,如果数据正确对齐且不大于机器字,大多数CPU指令将按照您描述的意义原子操作。
所以我不需要共享内存/变量的互斥保护?
您确实需要一些同步 - 无论是互斥还是使用原子操作ala std::atomic
。
原因包括:
如果你的变量不是volatile
,编译器甚至可能不会发出存储器地址的读写指令,这些存储器地址名义上在你可能期望的位置保存该变量,而是重用读取或设置的值。保存在CPU寄存器中或在编译时已知
std::atomic
类型,则不需要使用volatile
此外,即使数据写入内存,它也可能不会离开CPU缓存并被写入实际RAM,而其他内核和CPU可以看到它,除非您明确使用内存屏障({{1} }和std::mutex
类型为你做这些)
最后,读取和写入值之间的延迟可能会导致意外结果,因此像std::atomic
这样的操作可能会失败,正如David Schwartz所解释的那样。