gcc 中线程安全的原子操作

问题描述 投票:0回答:5

在我开发的一个程序中,我有很多代码如下:

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

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

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

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

c multithreading gcc atomic
5个回答
16
投票

您可以查看 gcc 文档。对于当前的 gcc 版本(4.3.2),它将是第 5.47 章用于原子内存访问的内置函数 - 对于其他 gcc 版本,请检查您的文档。它应该在第 5 章 - C 语言家族的扩展中。

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


16
投票

在某种程度上,C 中的原子操作是通过atomic.h 标头直接从内核源代码提供的。

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

Tudor Golubenco 在他的博客上提供了非常好的解释。他甚至提供了初始atomic.h 文件的直接替换,以防您有一些代码需要它。

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


4
投票

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

你想要做的是通知编译器其他线程可能已经触及了这个内存位置。 (

pthread_mutex_lock
的副作用是告诉编译器其他线程可能已触及内存的任何部分。)您可能会看到推荐使用
volatile
,但这不在 C 规范中,并且 GCC 不会将
volatile
解释为方式。

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

是 GCC 特定的机制,表示“

variable
已写入,重新加载它”。


1
投票

AFAIK,你不能在 MOV 指令前加上 LOCK 前缀;这仅适用于 RMW 操作。但如果他确实使用简单的存储,他可能还需要一个内存屏障,这是隐式的互斥锁以及允许 LOCK 的指令。


0
投票

正如我所见,您正在使用 gnu 平台进行开发,因此可以肯定地说 glic 提供了具有原子功能的数据类型 int ,

'sig_atomic_t'
。因此,这种方法可以确保您在内核级别进行原子操作。不是 gcc 级别。

© www.soinside.com 2019 - 2024. All rights reserved.