簡體   English   中英

UNIX便攜式原子操作

[英]UNIX Portable Atomic Operations

在C中是否有(POSIX-)可移植方式用於原子變量操作,類似於使用pthread的可移植線程?

原子操作是像“遞增和獲取”這樣的操作,它們以原子方式執行,這意味着沒有上下文切換可以干擾操作。 在Linux內核空間中,我們必須使用atomic_t類型,在Java中我們有java.util.concurrent.atomic包。

在Linux上,atomic.h文件提供原子操作,但include依賴於平台,例如#include <asm-x86_64/atomic.h>並且它在Mac OS X上不能以類似的方式提供。

對於任何在未來偶然發現這種情況的人來說,C11原子是現在最好的方法 - 我相信它們將被納入GCC 4.9。

從C11開始,有一個可選的Atomic庫 ,它提供原子操作。 對於具有此可選功能的C11編譯器(如gcc-4.9)的任何平台,這都是可移植的。

可以使用__STDC_NO_ATOMICS__檢查原子是否存在以及是否存在<stdatomic.h>

atomic.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

既然你要求OS X:

(並且因為在這個帖子中引發了跨平台性。)

OS X具有OSAtomicAdd32()和朋友的功能。 它們在“/usr/include/libkern/OSAtomic.h”中聲明。 請參閱“線程編程”指南的 “使用原子操作”部分。

對於Windows,有InterlockedIncrement()和朋友(參見MSDN)。

與gcc builtins __sync_fetch_and_add()和朋友(已在上面鏈接)一起,您應該為每個主要桌面平台提供一些東西。

請注意,我自己還沒有使用它們,但可能會在接下來的幾天內使用它們。

不,POSIX沒有指定任何可移植的無鎖/原子操作。 這就是為什么他們有pthreads。

您要么必須使用非標准方式,要么堅持使用ptrheads來實現可移植性。

C11原子最小可運行的例子

通過在glibc 2.28中添加線程,我們可以在純C11中執行原子和線程。

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

main.c中

#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,所以事情應該在那里工作。

AFAIK沒有跨平台的方法來進行原子操作。 可能有一個圖書館,但我不知道。 不過,打自己的並不是特別難。

我不認為有。

許可證允許的一種解決方法是從Linux內核空間復制相關的每個體系結構實現。 我沒有密切關注這些原語的演變,但我猜它們確實是原語,即不依賴於內核中的其他服務或API。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM