【问题标题】:Atomic reads in CC中的原子读取
【发布时间】:2011-10-04 02:35:13
【问题描述】:

根据Are C++ Reads and Writes of an int Atomic?,由于处理器缓存的问题,整数的读取(以及指针——或者我假设)在 C 中不是原子的。所以,我的问题是有一些我可以用来使读取原子,还是我需要使用锁?我查看了几组原子操作库,但到目前为止,我还找不到原子读取的函数。

编辑:编译器: Clang 2.9 编辑:平台: x86(64 位)

谢谢。

【问题讨论】:

  • 如果是 GCC,你可以使用 are some features。我不会回答这个问题,因为我基本上是在重复别人的博客文章。
  • 我根据您上次的编辑更新了您的标签。
  • 注意术语。在正确对齐的内存上读取和写入 32 位结构 在 32+ 位平台上是原子的;也就是说,值不能在读取或写入的中途改变。 (大多数编译器正确对齐内存以实现这一点。)Clang 不能确保您获得的值与“最新”值一致,也不能确保读取和写入操作按照代码中显示的确切顺序发生。跨度>
  • 还有什么平台? ARM?
  • 真的有可能创造一个实际显示问题的情况吗?那会是什么样子?

标签: c multithreading concurrency atomic clang


【解决方案1】:

一般来说,原子操作库不提供简单的原子提取,因为它很少使用;您读取该值,然后对其执行某些操作,并且在此期间需要保持锁定,以便您知道您读取的值没有更改。因此,不是原子读取,而是执行锁定的某种原子测试和设置(例如gcc__sync_fetch_and_add()),然后您在持有锁定时执行正常的非同步读取。

例外情况是设备驱动程序,您可能必须实际锁定系统总线以获得相对于总线上其他设备的原子性,或者在实现原子操作库的锁定原语时;这些本质上是特定于机器的,您必须深入研究汇编语言。在 x86 处理器上,有各种原子指令,加上一个 lock 前缀,可应用于大多数访问内存并在操作期间持有总线锁的操作;其他平台(SPARC、MIPS 等)也有类似的机制,但通常细节不同。在这种情况下,您将必须了解您正在为其编程的 CPU,并且很可能必须了解有关机器总线架构的一些信息。并且用于此的库很少有意义,因为您不能在函数进入/退出之间保持总线或内存锁,即使使用宏库也必须小心,因为这意味着在宏调用之间可能会穿插正常操作可能会破坏锁定的事实。用汇编语言编写整个关键部分几乎总是更好。

【讨论】:

  • 问题是在某些系统上你不能得到正确的结果,除非你在读和写上做一些特殊的事情,也就是说,如果你正在做一个简短的计算,那么你做一个 CAS 所以你的只有在您工作时值没有改变时才会发生变化。
  • @Spudd86:我会将他们归为第二组,而不是第一组。
  • @geeksaur 我很确定这就是问题所在
  • @Spudd86:这就是为什么我对它们进行了讨论,这比另一个更长。
  • @Spudd86:稍微不那么简单:那里有两个问题,关于低级/asm 的东西,以及为什么图书馆没有原子读取,所以我解决了这两个问题。
【解决方案2】:

gcc 有一组原子内置函数,但它没有简单的原子提取,但是您可以执行类似 __sync_fetch_and_add(&<your variable here>, 0); 的操作来解决这个问题

GCC 文档是 here,上面有那篇博文

编辑:啊,clang,我知道 LLVM IR 中包含原子,但我不知道 clang 是否以任何方式公开它们,但可能值得一试,看看它是否抱怨使用 gcc 的,它可能会支持他们。编辑:嗯,它似乎有一些东西......clang docs 虽然没有 gcc 做那么多,但文档似乎暗示它也可能做 gcc 的。

【讨论】:

  • 值得注意的是,编译器在使用这些时会自动进行类型转换。 +1,但是唉..这是Clang :)
  • "Clang 支持许多与 GCC 语法相同的内置库函数,包括...、__sync_fetch_and_add 等。" clang.llvm.org/docs/LanguageExtensions.html#builtins
猜你喜欢
  • 2010-09-08
  • 1970-01-01
  • 2017-01-16
  • 1970-01-01
  • 1970-01-01
  • 2015-08-13
  • 1970-01-01
  • 2011-03-12
  • 1970-01-01
相关资源
最近更新 更多