C原子读取修改写入

4

在C语言中是否有用于原子读取-修改-写入的函数?我想要在单个原子块中读取一个值,然后将其设置为0。

对于C ++,有std::atomic :: exchange()正是我要找的东西。在C中是否有类似的内容?

以下是代码:

void interruptHandler(void) {
    /* Callback attached to 3rd party device driver, indicating hardware fault */
    /* Set global variable bit masked flag to indicate interrupt */
    faultsBitMask |= 0x1;
}

void auditPoll(*faults) {
    *faults = faultsBitMask;
    /* !!! Need to prevent interrupt pre-empt here !!! */
    /* Combine these two lines to a single read-modify-write? */
    faultsBitMask = 0;
}

目标架构是PowerPC。

感谢您的帮助!


2
C11标准添加了原子操作。如果你的编译器足够新,你可以使用它们。 - Some programmer dude
C11原子类型和操作已经与C++11规范一起指定。它们应该在C和C++之间具有二进制兼容性。 - Jens Gustedt
感谢@Someprogrammerdude和@JensGustedt! - Splaty
3个回答

5

是的,<stdatomic.h>头文件包含一个类型通用的函数atomic_exchange,它与C++版本非常相似:

_Atomic int n = 10;

#include <stdatomic.h>

int main(void) { return atomic_exchange(&n, 0); }

这并不是全部,当涉及到信号处理程序中的原子操作时需要特别小心。而且,对于你正在做的事情,你真的不需要原子交换,请参考我的答案。 - Jens Gustedt
@JensGustedt:嗯,这就是OP要求的。她没有说这是用于信号处理程序。 - Kerrek SB

2
似乎您想在信号处理程序中使用原子操作。如果 C11 原子类型是“无锁”的,那么它们可以做到这一点,但通常不是这样的。您可以使用 ATOMIC_INT_LOCK_FREE 来测试 int 的锁定情况。
对于您的情况,您甚至不需要原子交换函数。在原子变量上进行简单的读写操作可能已经足够了。
faultsBitMask |= 0x1;

这将始终是一个原子读取-修改-写入操作。


这是否取决于操作系统?语言本身是否没有在信号处理程序周围指定任何缓存失效的内容? - Grady Player
是的,只要宏定义表明您的数据类型是无锁的,这就是与平台无关的。 - Jens Gustedt
嗨Jens,这不是用于信号处理程序。interruptHandler()是来自第三方Broadcom SDK的回调。当Broadcom硬件设备出现故障并指示故障时,它会触发。 - Splaty
@Splaty,更好的是,这样你就不必检查无锁并将变量标识为“_Atomic”,这应该是您需要对代码进行的唯一更改。 - Jens Gustedt
嗯,我认为我仍然需要使用atomic_exchange()来进行读取和清除,对吧?{ *faults = faultsBitMask; faultsBitmask = 0; } - Splaty

1
如果你正在使用GCC,可以尝试使用GCC内建函数__atomic_exchange__atomic_compare_exchange_n

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接