web-dev-qa-db-ja.com

UNIXポータブルアトミック操作

Cには、pthreadを使用したポータブルスレッドに類似したアトミック変数操作用の(POSIX-)移植可能な方法はありますか?

アトミック操作は、アトミックに実行される「インクリメントとゲット」のような操作です。つまり、コンテキストスイッチが操作に干渉することはありません。 Linuxカーネルスペースでは、 atomic_t タイプ、Javaには Java.util.concurrent.atomic パッケージが必要です。

Linuxでは、atomic.hファイルはアトミック操作を提供しますが、インクルードはプラットフォームに依存します。 #include <asm-x86_64/atomic.h>と同様に、Mac OS Xでは使用できません。

30
dmeister

C11以降、アトミック操作を提供するオプションの Atomic library があります。これは、このオプション機能を備えた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
13
ecerulm

将来これに出くわす人にとって、C11アトミックはこれを行うための最良の方法です-私はそれらがGCC 4.9に含まれると信じています。

13
user3033869

OS Xを要求してから:

(そして、このスレッドでクロスプラットフォーム性が引き上げられて以来。)

OS Xには関数OSAtomicAdd32()とその友達がいます。 「/usr/include/libkern/OSAtomic.h」で宣言されています。 スレッディングプログラミングガイド のセクション「アトミック操作の使用」を参照してください。

Windowsの場合、InterlockedIncrement()とその仲間(MSDNを参照)があります。

Gccビルトイン__ sync_fetch_and_add()および友達(上記にリンクされています)とともに、すべてのメインデスクトッププラットフォームに何かが必要です。

私はまだ自分で使用していませんが、数日中に使用する可能性があることに注意してください。

10
someGuy

いいえ、POSIXはanyポータブルロックフリー/アトミック操作を指定していません。それがpthreadを持っている理由です。

非標準的な方法を使用するか、移植性のためにptrheadを使用する必要があります。

4
paxdiablo

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

非アトミック変数へのスレッド間のきちんとしたアクセスのため、非アトミックカウンターはアトミックカウンターよりも小さい可能性が非常に高いです。

Pthreadの例は次の場所にあります: プレーンCでスレッドを開始するにはどうすればよいですか?

ソースからglibcをコンパイルすることにより、Ubuntu 18.04(glibc 2.27)でテストされています: 単一のホスト上の複数のglibcライブラリ Ubuntu 18.10にはglibc 2.28があるため、そこでうまくいくはずです。

AFAIKには、アトミック操作を実行するためのクロスプラットフォームの方法はありません。そこに図書館があるかもしれませんが、私は知りません。自分でロールするのは特に難しいことではありません。

0
Goz

あるとは思いません。

それを解決する1つの方法は、もちろん許可するライセンスです。たとえば、関連するアーキテクチャごとの実装をコピーします。 Linuxカーネル空間。私はこれらのプリミティブの進化を厳密には追跡していませんが、それらが実際にプリミティブであること、つまり、カーネル内の他のサービスやAPIに依存していないことを推測します。

0
unwind