gcc中的线程安全原子操作

时间:2008-10-03 06:44:34

标签: multithreading gcc atomic

在我工作的程序中,我有很多代码如下:

pthread_mutex_lock( &frame->mutex );
frame->variable = variable;
pthread_mutex_unlock( &frame->mutex );

如果中间指令可以用原子存储替换,这显然是浪费CPU周期。我知道gcc非常有能力,但是我没能找到关于这种简单的线程安全原子操作的文档。我如何用原子操作替换这组代码?

(我知道简单的商店在理论上应该是原子的,但我不希望优化器在这个过程中的某个时刻不会搞砸他们的原子。)

澄清:我不需要它们是严格的原子;这些变量仅用于线程同步。也就是说,线程B读取值,检查它是否正确,如果不正确,它会休眠。因此,即使线程A更新了值并且线程B没有意识到它的更新,这也不是问题,因为这只是意味着线程B在它不需要时就会休眠,并且当它被唤醒时,值将会是对的。

5 个答案:

答案 0 :(得分:16)

您可以查看gcc文档。对于当前的gcc版本(4.3.2),它将是第5.47章Built-in functions for atomic memory access - 对于其他gcc版本,请查看您的文档。它应该在第5章C语言家族的扩展中。

顺便提一下,C编译器绝对不能保证简单的存储操作是原子的。你不能依赖这个假设。为了使机器操作码以原子方式执行,它需要LOCK前缀。

答案 1 :(得分:15)

在某一点上,C中的原子操作是通过atomic.h头直接从内核源提供的。

然而,直接在用户空间代码中使用内核头文件是一种非常糟糕的做法,因此不久前删除了atomic.h头文件。相反,我们现在可以使用“GCC Atomic Builtins”,这是一种更好,更可靠的方法。

有一个very good explanation provided by Tudor Golubenco on his blog。他甚至为初始的atomic.h文件提供了一个替代品,以防你有一些需要它的代码。

不幸的是我是stackoverflow的新手,所以我只能在评论中使用一个链接,所以请查看Tudor的帖子并获得启发。

答案 2 :(得分:4)

在x86和大多数其他架构上,对齐的4字节读写始终是原子的。但优化器可能会在单个线程内跳过/重新排序读取和写入。

您要做的是通知编译器其他线程可能已触及此内存位置。 (pthread_mutex_lock的副作用是告诉编译器其他线程可能已经触及了内存的任何部分。)您可能会看到推荐volatile,但这不在C规范中,并且GCC不解释volatile那样。

asm("" : "=m" (variable));
frame->variable = variable;

是一个特定于GCC的机制,可以说“variable已写入,重新加载”。

答案 3 :(得分:1)

AFAIK,您不能使用LOCK为MOV指令添加前缀;这仅适用于RMW操作。但是,如果他 使用一个简单的商店,他可能还需要一个内存屏障,这是隐含的互斥锁,以及允许LOCK的指令。

答案 4 :(得分:0)

正如我所看到的,您正在使用gnu平台进行开发,因此可以肯定地说glic提供的数据类型为int,其范围为原子能力'sig_atomic_t'。因此,这种方法可以确保您在内核级别进行原子操作。不是gcc级别。