如何在 C 中进行原子增量和获取?

发布于 2024-08-23 19:55:57 字数 179 浏览 5 评论 0原文

我正在寻找一种方法来自动增加短路,然后返回该值。我需要在内核模式和用户模式下执行此操作,因此它是在 Linux 下、Intel 32 位架构上用 C 语言编写的。不幸的是,由于速度要求,互斥锁不是一个好的选择。

还有其他方法可以做到这一点吗?此时,唯一可用的选项似乎是内联一些程序集。如果是这样的话,有人可以指出我适当的说明吗?

I'm looking for a way to atomically increment a short, and then return that value. I need to do this both in kernel mode and in user mode, so it's in C, under Linux, on Intel 32bit architecture. Unfortunately, due to speed requirements, a mutex lock isn't going to be a good option.

Is there any other way to do this? At this point, it seems like the only option available is to inline some assembly. If that's the case, could someone point me towards the appropriate instructions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

可遇━不可求 2024-08-30 19:55:57

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

反汇编分析位于:How我可以用纯 C 启动线程吗?

在 Ubuntu 18.10、GCC 8.2.0、glibc 2.28 中测试。

C11 _Atomic

在 5.1 中,上述代码适用于:

_Atomic int global = 0;
global++;

glibc 2.28 中添加了 C11 threads.h,它允许您在没有 POSIX 的纯 ANSI C,最小可运行示例: How do我用纯 C 启动线程?

GCC __atomic_* built-ins

As of GCC 4.8, __sync built-ins have been deprecated in favor of the __atomic built-ins: https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fatomic-Builtins.html

They implement the C++ memory model, and std::atomic uses them internally.

The following POSIX threads example fails consistently with ++ on x86-64, and always works with _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;
}

Compile and run:

gcc -std=c99 -Wall -Wextra -pedantic -o main.out ./main.c -pthread
./main.out

Disassembly analysis at: How do I start threads in plain C?

Tested in Ubuntu 18.10, GCC 8.2.0, glibc 2.28.

C11 _Atomic

In 5.1, the above code works with:

_Atomic int global = 0;
global++;

And C11 threads.h was added in glibc 2.28, which allows you to create threads in pure ANSI C without POSIX, minimal runnable example: How do I start threads in plain C?

想念有你 2024-08-30 19:55:57

GCC 支持原子操作:

gcc 原子

GCC supports atomic operations:

gcc atomics

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文