web-dev-qa-db-ja.com

x86、arm、GCC、iccで動作するLinuxでアトミック操作を実行する方法は?

現代のすべてのOSは今日、いくつかのアトミック操作を提供しています。

  • WindowsにはInterlocked* AP​​Iがあります
  • FreeBSDには<machine/atomic.h>があります
  • Solarisには<atomic.h>があります
  • Mac OS Xには<libkern/OSAtomic.h>があります

Linuxでそのようなことはありますか?

  • X86、x86_64、およびarmなど、ほとんどのLinuxサポートプラットフォームで動作するために必要です。
  • 少なくともGCCとIntelコンパイラで動作する必要があります。
  • Glibやqtのような3番目のparライブラリを使用する必要はありません。
  • C++で動作するために必要です(Cは不要です)

問題点:

  • GCCアトミックビルトイン__sync_*は、すべてのプラットフォーム(ARM)でサポートされておらず、Intelコンパイラーでもサポートされていません。
  • AFAIK <asm/atomic.h>はユーザー空間では使用すべきではありません。また、まったく使用していません。また、Intelコンパイラで動作するかどうかもわかりません。

提案はありますか?

関連する質問がたくさんあることは知っていますが、そのうちのいくつかは__sync*を指しており、これは私にとっては現実的ではありません(ARM)およびasm/atomic.hを指しています。

多分GCCのためにこれを行うインラインアセンブリライブラリがあります(ICCはgccアセンブリをサポートしています)?

編集:

追加操作に対してのみ非常に部分的なソリューションがあります(アトミックカウンターの実装は許可しますが、CASを必要とするフリー構造のロックは許可しません)。

libstc++を使用する場合(インテル®コンパイラーはlibstdc++を使用します)、__gnu_cxx::__exchange_and_addまたは<ext/atomicity.h>で定義された<bits/atomicity.h>を使用できます。コンパイラのバージョンに依存します。

ただし、CASをサポートする何かを見たいです。

55
Artyom

プロジェクトはこれを使用しています:

http://packages.debian.org/source/sid/libatomic-ops

CASなどの単純な操作が必要な場合は、カーネルからArch固有の実装を使用するだけで、autotools/cmakeを使用してユーザー空間でArchチェックを実行できませんか?ライセンスに関しては、カーネルはGPLですが、これらの操作のインラインアセンブリはIntel/AMDによって提供されるのではなく、カーネルにライセンスがあるというのは間違いないと思います。それらはカーネルソースで簡単にアクセスできる形式になっています。

19
Noah Watkins

C&C++の最近の標準(2011年以降)では、アトミック操作が指定されています。

とにかく、ご使用のプラットフォームまたはコンパイラーがこれらの新しいヘッダーと機能をサポートしていない場合があります。

13
kevinarpe

くそーGCCプリミティブを提案するつもりだったのですが、それらは立ち入り禁止だと言いました。 :-)

その場合、#ifdef気にするアーキテクチャ/コンパイラの組み合わせごとに、インラインasmをコーディングします。そして、__GNUC__または同様のマクロがあり、GCCプリミティブが使用可能な場合はそれを使用します。これらを使用する方がはるかに適切だと感じているためです。 :-)

多くの重複があり、正確性を確認するのは難しいかもしれませんが、これは多くのプロジェクトがこれを行う方法であるようであり、私はそれで良い結果を得ました。

過去に私を苦しめたいくつかの落とし穴:GCCを使用するときは、「asm volatile "および"memory"および"cc"など.

3
asveikau

ARMアトミック操作をサポートするためのGCCのパッチがあります。Intelでは役に立ちませんが、コードを調べることができます-古いARMアーキテクチャ、および新しいアーキテクチャには命令が組み込まれているため、動作するものをビルドできるはずです。

http://gcc.gnu.org/ml/gcc-patches/2011-07/msg00050.html

1
Justin Cormack

Boostは非侵入型のライセンスを持ち、他のフレームワークは既にターゲットプラットフォームでサポートされている限り、移植可能なアトミックカウンターを提供しています。

サードパーティのライブラリは私たちに適しています。そして、奇妙な理由で会社がそれらを使用することを禁じている場合でも、あなたが探しているものを実装するためにそれらがどのように進むかを見ることができます(ライセンスがあなたの使用を許可する限り)。

1
Luc Hermitte

__sync*は確かにIntelコンパイラによってサポートされています(GCCはそこからこれらのビルドインを採用しているため)。最初の段落を読む このページ 。 「 Intel®C++ Compiler for Linux * Intrinsics Reference 」、198ページも参照してください。これは2006に由来し、作成されたものを正確に説明しています。 -ins。

ARMサポートについては、古いARM CPUの場合:ユーザー空間で完全に実行することはできませんが、カーネル領域で実行できます(操作中の割り込みを無効にすることにより) 、そして私はどこかでそれがかなり長い間サポートされていると読んだと思います。

this PHP bug 、2011-10-08日付、__sync_*は失敗するだけです

  • Linux以外でのPA-RISC
  • SPARCv7以前
  • GCC <4.3のARM
  • Linux以外のARMv5以前
  • MIPS1

したがって、GCC> 4.3(および4.7が現在のもの)であれば、ARMv6以降では問題はないはずです。 Linux向けにコンパイルしている限り、ARMv5でも問題はないはずです。

1
Mecki

私は最近そのようなことを実装しましたが、あなたと同じ困難に直面しました。私の解決策は基本的に次のとおりでした:

  • 機能マクロでgccビルトインを検出しよう
  • 利用できない場合は、他のアーキテクチャ用に___asm___を使用してcmpxchのようなものを実装するだけです(ARMはそれよりも少し複雑です)。 sizeof(int)のような1つの可能なサイズに対してそれを行ってください。
  • inline関数を使用して、1つまたは2つのプリミティブの上に他のすべての機能を実装します
1
Jens Gustedt

Debian/Ubuntuの推奨事項...

Sudo apt-get install libatomic-ops-dev

例: http://www.hpl.hp.com/research/linux/atomic_ops/example.php4

GCCおよびICC互換。

atomic <T>を使用するIntelスレッドビルディングブロック(TBB)と比較して、libatomic-ops-devは2倍以上高速です! (Intelコンパイラー)

TBBの1.2秒に対して、0.5秒で1000万intのリングバッファー接続をパイピングするUbuntu i7プロデューサー-コンシューマスレッドでのテスト

使いやすい.

揮発性AO_tヘッド。

AO_fetch_and_add1(&head);

0
user1408985

kernel_user_helpers.txt または entry-arm.c を参照して、__kuser_cmpxchg。他のARM Linuxバージョン、

kuser_cmpxchg

場所:0xffff0fc0 
 
参照プロトタイプ:
 
 int __kuser_cmpxchg(int32_t oldval、int32_t newval、volatile int32_t * ptr); 
 
入力:
 
 r0 = oldval 
 r1 = newval 
 r2 = ptr 
 lr =返信先アドレス
 
 Output:
 
 r0 =成功コード(ゼロまたは非ゼロ)
 Cフラグ= r0 == 0の場合セット、r0!= 0の場合クリア
 
不正なレジスタ:
 
 r3、ip、flags 
 
 Definition:
 
 * ptrがoldvalと等しい場合のみ、newvalを原子的に* ptrに格納します。
 * ptrが変更された場合はゼロを返し、交換が行われなかった場合はゼロ以外を返します。
呼び出しコードでのアセンブリ
最適化を許可するように変更されました。
 
使用例:
 typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
 #define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)

 int atomic_add(volatile int *ptr, int val)
 {
        int old, new;

        do {
                old = *ptr;
                new = old + val;
        } while(__kuser_cmpxchg(old, new, ptr));

        return new;
}

注:

  • このルーチンには、必要に応じてすでにメモリバリアが含まれています。
  • __kuser_helper_version> = 2の場合のみ有効です(カーネルバージョン2.6.12以降)。

これは、swpプリミティブを使用するARMv3を搭載したLinuxで使用するためのものです。これをサポートしないためには、非常に古いARMが必要です。data abortまたはinterruptスピンが失敗する可能性があるため、カーネルはこのアドレス〜0xffff0fc0を監視し、ユーザースペースPCdata abortまたはinterruptが発生した場合の修正ARMv5以前をサポートするすべてのユーザー空間ライブラリは、この機能を使用します。

たとえば、QtConcurrentはこれを使用します。

0
artless noise