multithreading gcc 中的线程安全原子操作
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/165931/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Thread-safe atomic operations in gcc
提问by Dark Shikari
In a program I work on, I have a lot of code as follows:
在我工作的程序中,我有很多代码如下:
pthread_mutex_lock( &frame->mutex );
frame->variable = variable;
pthread_mutex_unlock( &frame->mutex );
This is clearly a waste of CPU cycles if the middle instruction can just be replaced with an atomic store. I know that gcc is quite capable of this, but I haven't been able to find much documentation on such simple thread-safe atomic operations. How would I replace this set of code with an atomic operation?
如果可以用原子存储替换中间指令,这显然是浪费 CPU 周期。我知道 gcc 非常有能力做到这一点,但我一直无法找到关于这种简单的线程安全原子操作的大量文档。我将如何用原子操作替换这组代码?
(I know that simple stores should theoretically be atomic, but I don't want to have to hope that the optimizer isn't screwing up their atomic-ness at some point in the process.)
(我知道简单的存储理论上应该是原子的,但我不想希望优化器不会在过程中的某个时刻搞砸它们的原子性。)
Clarification: I do not need them to be strictly atomic; these variables are solely used for thread synchronization. That is, Thread B reads the value, checks if its correct, and if its not correct, it sleeps. So even if Thread A updates the value and Thread B doesn't realize its updated, that isn't a problem, since that just means Thread B sleeps when it didn't really need to, and when it wakes up, the value will be correct.
澄清:我不需要它们是严格原子的;这些变量仅用于线程同步。也就是说,线程 B 读取该值,检查其是否正确,如果不正确,则休眠。所以即使线程 A 更新了值而线程 B 没有意识到它的更新,那也不是问题,因为这只是意味着线程 B 在它并不真正需要的时候休眠,当它醒来时,该值将是正确的。
回答by Mihai Limb??an
You could check the gcc documentation. For the current gcc version (4.3.2) it would be chapter 5.47 Built-in functions for atomic memory access- for other gcc versions please check your docs. It should be in chapter 5- Extensions to the C Language Family.
您可以查看 gcc 文档。对于当前的 gcc 版本 (4.3.2),它将是第 5.47 章用于原子内存访问的内置函数- 对于其他 gcc 版本,请查看您的文档。它应该在第 5 章 - C 语言族的扩展中。
Incidentally, the C compiler makes absolutely no guarantee as to simple store operations being atomic. You cannot rely on that assumption. In order for a machine opcode to be executed atomically, it needs the LOCK prefix.
顺便说一下,C 编译器绝对不能保证简单的存储操作是原子的。你不能依赖这个假设。为了原子地执行机器操作码,它需要 LOCK 前缀。
回答by Valeriu Palo?
Up to a certain point, atomic operations in C were provided straight from the kernel sources via the atomic.h header.
在某种程度上,C 中的原子操作是通过 atomic.h 头文件直接从内核源代码提供的。
However, having kernel headers being used directly in user-space code is a very bad practice, so the atomic.h header file was removed some time ago. Instead we ca now make use of the "GCC Atomic Builtins" which are a far better and more reliable approach.
但是,在用户空间代码中直接使用内核头文件是一种非常糟糕的做法,因此不久前删除了 atomic.h 头文件。相反,我们现在可以使用“GCC Atomic Builtins”,这是一种更好、更可靠的方法。
There is a very good explanation provided by Tudor Golubenco on his blog. He even provides a drop-in replacement for the initial atomic.h file, in case you have some code that needs it.
有一个由铎Golubenco在他的博客提供了很好的解释。他甚至提供了初始 atomic.h 文件的替代品,以防您有一些需要它的代码。
Unfortunately I'm new to stackoverflow, so I can only use one link in my comments, so check Tudor's post and get enlightened.
不幸的是,我是 stackoverflow 的新手,所以我只能在我的评论中使用一个链接,所以请查看 Tudor 的帖子并获得启发。
回答by ephemient
On x86 and most other architectures, aligned 4-byte reads and writes are always atomic. The optimizer may skip/reorder reads and writes within a single thread, though.
在 x86 和大多数其他架构上,对齐的 4 字节读取和写入始终是原子的。不过,优化器可能会跳过/重新排序单个线程内的读取和写入。
What you want to do is inform the compiler that other threads may have touched this memory location. (A side effect of pthread_mutex_lock
is telling the compiler that other threads may have touched any part of memory.) You may see volatile
recommended, but this not in the C specification, and GCC doesn't interpret volatile
that way.
你想要做的是通知编译器其他线程可能已经触及了这个内存位置。(一个副作用pthread_mutex_lock
是告诉编译器其他线程可能已经接触了内存的任何部分。)您可能会看到volatile
推荐的,但这不在 C 规范中,并且 GCC 不会以volatile
这种方式解释。
asm("" : "=m" (variable));
frame->variable = variable;
is a GCC-specific mechanism to say that "variable
has been written to, reload it".
是一种特定于 GCC 的机制,表示“variable
已写入,重新加载”。
回答by zvrba
AFAIK, you can't prefix MOV instructions with LOCK; this is allowed only for RMW operations. But if he doesuse a simple store, he might also need a memory barrier, which is implicit with mutex, as well as with instructions that allow LOCK.
AFAIK,你不能用 LOCK 前缀 MOV 指令;这仅适用于 RMW 操作。但是如果他确实使用了一个简单的存储,他可能还需要一个内存屏障,它隐含在互斥锁中,以及允许 LOCK 的指令中。
回答by erick2red
As i can see, you're using gnu platform for development, so it's safe to say that glic provides a datatype int ranged with atomic capabilities, 'sig_atomic_t'
. So this approach can assure you atomic operations at kernel levels. not gcc levels.
正如我所看到的,您正在使用 gnu 平台进行开发,因此可以肯定地说 glic 提供了一个具有原子能力范围的数据类型 int,'sig_atomic_t'
. 因此,这种方法可以确保您在内核级别进行原子操作。不是 gcc 级别。