我想寻找一种方式来原子地增加一个short类型的值,并返回该值。我需要在内核模式和用户模式下都这样做,因此代码是基于Linux系统,在Intel 32位架构下编写的C语言。不幸的是,由于速度要求,使用互斥锁并不是一个好的选择。
是否有其他方法可以实现这个目标?目前看来唯一可行的选择是嵌入一些汇编代码。如果是这种情况,能否给我指出适当的汇编指令?
GCC __atomic_*
内建函数
从GCC 4.8开始,__sync
内建函数已被弃用,改为使用 __atomic
内建函数: https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fatomic-Builtins.html
它们实现了C++的内存模型,并被std::atomic在内部使用。
以下POSIX线程示例在x86-64上使用++
会一直失败,而使用_atomic_fetch_add
则始终成功。
main.c
#include <assert.h>
#include <pthread.h>
#include <stdlib.h>
enum CONSTANTS {
NUM_THREADS = 1000,
NUM_ITERS = 1000
};
int global = 0;
void* main_thread(void *arg) {
int i;
for (i = 0; i < NUM_ITERS; ++i) {
__atomic_fetch_add(&global, 1, __ATOMIC_SEQ_CST);
/* This fails consistently. */
/*global++*/;
}
return NULL;
}
int main(void) {
int i;
pthread_t threads[NUM_THREADS];
for (i = 0; i < NUM_THREADS; ++i)
pthread_create(&threads[i], NULL, main_thread, NULL);
for (i = 0; i < NUM_THREADS; ++i)
pthread_join(threads[i], NULL);
assert(global == NUM_THREADS * NUM_ITERS);
return EXIT_SUCCESS;
}
编译并运行:
gcc -std=c99 -Wall -Wextra -pedantic -o main.out ./main.c -pthread
./main.out
在如何在纯C中启动线程?的页面上进行反汇编分析。
在Ubuntu18.10、GCC8.2.0、GLIBC2.28上进行测试。
C11 _Atomic
在5.1中,以上代码适用于:
_Atomic int global = 0;
global++;
C11 threads.h
在glibc 2.28中被添加,它允许您在纯ANSI C中创建线程而无需使用POSIX。最小可运行示例:How do I start threads in plain C?
__sync_add_and_fetch
听起来像OP想要的。 - caf