Multithreading gcc中的线程安全原子操作

Multithreading gcc中的线程安全原子操作,multithreading,gcc,atomic,Multithreading,Gcc,Atomic,在我工作的一个程序中,我有很多代码,如下所示: pthread_mutex_lock( &frame->mutex ); frame->variable = variable; pthread_mutex_unlock( &frame->mutex ); 如果中间指令可以用原子存储代替,这显然是对CPU周期的浪费。我知道gcc很有能力做到这一点,但我还没有找到太多关于这种简单的线程安全原子操作的文档。如何用原子操作替换这组代码 (我知道简单存储理论上应该是原子

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

pthread_mutex_lock( &frame->mutex );
frame->variable = variable;
pthread_mutex_unlock( &frame->mutex );
如果中间指令可以用原子存储代替,这显然是对CPU周期的浪费。我知道gcc很有能力做到这一点,但我还没有找到太多关于这种简单的线程安全原子操作的文档。如何用原子操作替换这组代码

(我知道简单存储理论上应该是原子的,但我不希望优化器在这个过程中的某个时候没有破坏它们的原子性。)


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

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


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

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

在x86和大多数其他体系结构上,对齐的4字节读写总是原子的。不过,优化器可能会跳过/重新排序单个线程内的读写操作

您要做的是通知编译器,其他线程可能已经接触到这个内存位置。(
pthread\u mutex\u lock
的一个副作用是告诉编译器其他线程可能已经接触了内存的任何部分。)您可能会看到
volatile
推荐,但这不在C规范中,GCC不会这样解释
volatile

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

是一种特定于GCC的机制,表示“
变量
已写入,请重新加载它”。

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

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

有一个问题。他甚至为初始的atomic.h文件提供了一个替换文件,以防您有一些代码需要它


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

正如我所看到的,您正在使用gnu平台进行开发,所以可以肯定地说,glic提供了一个包含原子功能的数据类型int,
'sig\u atomic\u t'
。因此,这种方法可以确保在内核级别执行原子操作。不是gcc级别。

除此之外,处理器的缓存可能会隐藏或重新排序相对于其他处理器的读写操作。。。因此需要一个内存围栏。pthread_mutex_lock提供了这一功能,但它非常依赖于体系结构。此外,ICC还支持用于原子内存访问的内置函数(如果您希望编译器可移植)。对于GCC,我认为从4.1开始就支持原子函数,所以一定要有一些ifdef来确保GCC或icc版本!那么,在并发访问的情况下,\同步\添加\和\获取不可靠?而且我们必须在程序集内联中直接使用lock addx?自从内核2.6以来,当互斥对象是空闲的时,互斥对象的成本几乎是零。无论如何,“\uuuu sync\u lock\u test\u and\u set”(因为gcc 4.1)应该可以做到这一点,这并不是在这种情况下可以使用的唯一功能。顺便说一句,原子存储或原子存储似乎更合适。
sig\u atomic\u t
仅在信号方面是原子的。它不是线程安全的。