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编译器绝对不能保证简单的存储操作是原子的。我们不能依赖该假设。为了原子地执行机器操作码,它需要LOCK前缀。
AFAIK,我们不能在MOV指令前加上LOCK;这仅适用于RMW操作。但是,如果他确实使用简单的存储,则可能还需要一个内存屏障,该屏障在互斥锁以及允许LOCK的指令中是隐含的。
在x86和大多数其他体系结构上,对齐的4字节读取和写入始终是原子的。不过,优化器可以跳过/重新排序单个线程中的读取和写入。
我们要做的是通知编译器其他线程可能已经触及了此内存位置。 (" pthread_mutex_lock"的副作用是告诉编译器其他线程可能已经接触到内存的任何部分。)我们可能会看到" volatile"的建议,但在C规范中却没有,并且GCC不会解释" volatile"的含义。道路。
asm("" : "=m" (variable)); frame->variable = variable;
是GCC专用的机制,可以说"变量已被写入,然后重新加载"。
直到一定程度,C语言中的原子操作都是直接通过atomic.h标头从内核源代码中提供的。
但是,直接在用户空间代码中使用内核头是非常糟糕的做法,因此前一段时间删除了atomic.h头文件。相反,我们现在可以使用" GCC原子内置函数",这是一种更好,更可靠的方法。
Tudor Golubenco在他的博客上提供了很好的解释。如果我们有一些需要的文件,他甚至提供了替换原始atomic.h文件的替代品。
不幸的是,我是stackoverflow的新手,所以我只能在评论中使用一个链接,因此请查看Tudor的文章并获得启发。
如我所见,我们正在使用gnu平台进行开发,因此可以肯定地说glic提供了一个具有原子功能'sig_atomic_t'的数据类型int。因此,这种方法可以确保我们在内核级别执行原子操作。不是gcc级别。