C 中的原子读取
编辑:编译器: Clang 2.9 编辑:平台: x86(64 位)
谢谢。
According to Are C++ Reads and Writes of an int Atomic?, due to issues of processor caching, reads of ints (and thusly pointers--or so I assume) are not atomic in C. So, my question is is there some assembly that I could use to make the read atomic, or do I need to use a lock? I looked at several sets of libraries of atomic operations, and, as of yet, I am unable to find a function for an atomic read.
EDIT: Compiler: Clang 2.9
EDIT: Platform: x86 (64-bit)
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
一般来说,原子操作库不提供简单的原子获取,因为它很少使用;您读取该值,然后对其执行某些操作,并且在此期间需要保持锁定,以便您知道您读取的值没有更改。因此,不是原子读取,而是某种执行锁定的原子测试和设置(例如 gcc 的 __sync_fetch_and_add()),然后执行当您持有锁时,正常的非同步读取。
设备驱动程序是个例外,您可能必须实际锁定系统总线才能获得相对于总线上其他设备的原子性,或者在实现原子操作库的锁定原语时;这些本质上是特定于机器的,您必须深入研究汇编语言。在 x86 处理器上,有各种原子指令,以及可应用于大多数访问内存并在操作期间保持总线锁的操作的
lock
前缀;其他平台(SPARC、MIPS 等)也有类似的机制,但细节通常有所不同。在这种情况下,您必须了解正在编程的 CPU,并且很可能必须了解有关机器的总线体系结构的信息。而用于此目的的库很少有意义,因为您无法在函数入口/出口之间保持总线或内存锁,即使使用宏库,也必须小心,因为这意味着在宏调用之间可能会散布正常操作。事实上这可能会破坏锁定。用汇编语言编写整个关键部分几乎总是更好。In general, a simple atomic fetch isn't provided by atomic operations libraries because it's rarely used; you read the value and then do something with it, and the lock needs to be held during that something so that you know that the value you read hasn't changed. So instead of an atomic read, there is an atomic test-and-set of some kind (e.g.
gcc
's__sync_fetch_and_add()
) which performs the lock, then you perform normal unsynchronized reads while you hold the lock.The exception is device drivers where you may have to actually lock the system bus to get atomicity with respect to other devices on the bus, or when implementing the locking primitives for atomic operations libraries; these are inherently machine-specific, and you'll have to delve into assembly language. On x86 processors, there are various atomic instructions, plus a
lock
prefix that can be applied to most operations that access memory and hold a bus lock for the duration of the operation; other platforms (SPARC, MIPS, etc.) have similar mechanisms, but often the fine details differ. You will have to know the CPU you're programming for and quite probably have to know something about the machine's bus architecture in this case. And libraries for this rarely make sense, because you can't hold bus or memory locks across function entry/exit, and even with a macro library one has to be careful because of the implication that one could intersperse normal operations between macro calls when in fact that could break locking. It's almost always better to just code the entire critical section in assembly language.gcc 有一组原子内置函数,但它没有简单的原子获取,但是您可以执行类似
__sync_fetch_and_add(&, 0);
的操作来解决这个问题GCC 文档为 这里上面有一篇博客文章
编辑:啊,clang,我知道 LLVM IR 中有原子,但我不知道 clang 是否以任何方式暴露它们,但可能是值得一试,看看它是否抱怨使用 gcc 的,它可能会支持它们。编辑:嗯,它似乎有一些东西...... clang docs 不做与 gcc 一样多,并且文档似乎表明它也可以做 gcc 的。
gcc has a set of atomic builtin functions, but it does not have a plain atomic fetch, however you could do something like
__sync_fetch_and_add(&<your variable here>, 0);
to work around thatGCC docs are here and there's that blog post above
EDIT: Ah, clang, I know LLVM IR has atomics in it, but I don't know if clang exposes them in any way, but it might be worth a shot to see if it complains about using the gcc ones, it might support them. EDIT: hmm it seems to have something... clang docs doesn't do as much as gcc though, and the docs seem to suggest it may also do the gcc ones.