31

C 中是否有一种(POSIX-)可移植方式用于原子变量操作,类似于使用 pthread 的可移植线程?

原子操作是诸如“递增和获取”之类的操作,它们以原子方式执行,这意味着没有上下文切换可以干扰操作。在 Linux 内核空间中,我们有atomic_t类型,在 Java 中我们有java.util.concurrent.atomic包。

在 Linux 上,atomic.h 文件提供原子操作,但包含依赖于平台,例如#include <asm-x86_64/atomic.h>,它在 Mac OS X 上以类似的方式不可用。

4

7 回答 7

14

对于将来偶然发现这一点的任何人,C11 原子是现在最好的方法——我相信它们将包含在 GCC 4.9 中。

于 2013-11-25T20:11:54.243 回答
14

从 C11 开始,有一个可选的Atomic 库提供原子操作。这可以移植到任何具有 C11 编译器(如 gcc-4.9)和此可选功能的平台。

可以检查原子__STDC_NO_ATOMICS__的存在和存在<stdatomic.h>

原子的.c

#include <stdio.h>
#include <stdlib.h>
#ifndef __STDC_NO_ATOMICS__
#include <stdatomic.h>
#endif

int main(int argc, char**argv) {
    _Atomic int a;
    atomic_init(&a, 42);
    atomic_store(&a, 5);
    int b = atomic_load(&a);
    printf("b = %i\n", b);

    return EXIT_SUCCESS;
}

编译器调用

clang -std=c11 atomic.c
gcc -std=c11 atomic.c
于 2015-01-28T21:14:34.050 回答
10

由于您要求使用 OS X:

(并且由于在此线程中提出了跨平台性。)

OS X 有函数OSAtomicAdd32()和朋友。它们在“/usr/include/libkern/OSAtomic.h”中声明。请参阅线程编程指南,“使用原子操作”部分。

对于 Windows,有InterlockedIncrement()和朋友(参见 MSDN)。

连同 gcc 内置函数 __sync_fetch_and_add()和朋友(已在上面链接),您应该为每个主要桌面平台提供一些东西。

请注意,我自己还没有使用它们,但可能会在接下来的几天内使用它们。

于 2010-09-07T15:36:54.700 回答
4

不,POSIX 没有指定任何可移植的无锁/原子操作。这就是为什么他们有pthreads。

您要么必须使用非标准方式,要么坚持使用 ptrheads 以获得可移植性。

于 2009-07-15T08:31:56.400 回答
3

C11 atomics 最小可运行示例

通过在 glibc 2.28 中添加线程,我们可以在纯 C11 中执行原子和线程。

示例来自:https ://en.cppreference.com/w/c/language/atomic

主程序

#include <stdio.h>
#include <threads.h>
#include <stdatomic.h>

atomic_int acnt;
int cnt;

int f(void* thr_data)
{
    for(int n = 0; n < 1000; ++n) {
        ++cnt;
        ++acnt;
        // for this example, relaxed memory order is sufficient, e.g.
        // atomic_fetch_add_explicit(&acnt, 1, memory_order_relaxed);
    }
    return 0;
}

int main(void)
{
    thrd_t thr[10];
    for(int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for(int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);

    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

编译并运行:

gcc -std=c11 main.c -pthread
./a.out

可能的输出:

The atomic counter is 10000
The non-atomic counter is 8644

由于跨线程对非原子变量的快速访问,非原子计数器很可能小于原子计数器。

可以在以下位置找到 pthreads 示例:如何在纯 C 中启动线程?

通过从源代码编译 glibc 在 Ubuntu 18.04 (glibc 2.27) 中进行测试:单个主机上的多个 glibc 库Ubuntu 18.10 具有 glibc 2.28,所以应该可以在那里工作。

于 2019-02-13T22:07:51.967 回答
0

AFAIK 没有跨平台的方法来进行原子操作。那里可能有一个图书馆,但我不知道。不过,自己动手并不是特别难。

于 2009-07-15T08:01:50.753 回答
0

我不认为有。

解决它的一种方法,当然许可证允许,是从例如 Linux 内核空间复制相关的每架构实现。我没有密切关注这些原语的演变,但我猜它们确实是原语,即不依赖于内核中的其他服务或 API。

于 2009-07-15T08:04:37.500 回答