56

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

  • WindowsにはInterlocked*APIがあります
  • FreeBSD には<machine/atomic.h>
  • ソラリスは<atomic.h>
  • Mac OS X には<libkern/OSAtomic.h>

Linuxの場合、そのようなものはありますか?

  • x86、x86_64、 armなど、ほとんどの Linux 対応プラットフォームで動作する必要があります 。
  • 少なくとも GCC と Intel Compiler で動作する必要があります。
  • glib や qt のような 3rd par ライブラリを使用する必要はありません。
  • C++ で動作させる必要があります (C は必要ありません)

問題:

  • GCC アトミック ビルトイン__sync_*は、すべてのプラットフォーム (ARM) でサポートされているわけではなく、Intel コンパイラでもサポートされていません。
  • 私の知る限り<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 をサポートするものを見たいと思っています。

4

9 に答える 9

19

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

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

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

于 2011-01-13T19:16:18.283 に答える
3

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

その場合、関心のある#ifdefアーキテクチャとコンパイラの組み合わせごとに実行し、インライン asm をコーディングします。そして__GNUC__、似たようなマクロをチェックして、利用可能な場合は GCC プリミティブを使用します。:-)

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

過去に私を悩ませたいくつかの落とし穴: GCC を使用するときは、" " と となどのclobbers を忘れないでください。asm volatile"memory""cc"

于 2010-02-18T09:36:04.270 に答える
1

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

サードパーティのライブラリは私たちにとって良いものです。また、奇妙な理由で会社がそれらの使用を禁止している場合でも、(ライセンスで使用が許可されている限り) 探しているものを実装する方法を確認できます。

于 2010-02-18T12:09:50.623 に答える
1

__sync*GCC はそこからこれらのビルトインを採用したため、確かに Intel コンパイラによってサポートされています (そしてサポートされています)。このページの最初の段落を読んでください。198 ページの「インテル® C++ コンパイラー Linux* 用組み込み関数のリファレンス」も参照してください。これは2006 年のもので、これらのビルトインについて正確に説明しています。

ARM サポートに関しては、古い ARM CPU の場合: ユーザー空間で完全に行うことはできませんが、(操作中に割り込みを無効にすることにより) カーネル空間で行うことができます。

2011 年 10 月 8日付けのこの PHP バグによると、次の__sync_*場合にのみ失敗します。

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

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

于 2012-04-12T02:17:06.320 に答える
1

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

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

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

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

于 2012-03-16T13:35:22.560 に答える
0

Debian/Ubuntu で推奨...

sudo apt-get install libatomic-ops-dev

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

GCC & ICC 互換。

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

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

そして使いやすい例えば

揮発性 AO_t ヘッド;

AO_fetch_and_add1(&head);

于 2012-05-21T23:33:52.780 に答える
0

参照: 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 = 古い値
  r1 = newval
  r2 = ptr
  lr = 返送先住所

出力:

  r0 = 成功コード (ゼロまたは非ゼロ)
  C フラグ = r0 == 0 の場合はセット、r0 != 0 の場合はクリア

破壊されたレジスタ:

  r3、ip、フラグ

意味:

  *ptr が oldval と等しい場合にのみ、newval を *ptr に原子的に格納します。
  *ptr が変更された場合はゼロを返し、交換が行われなかった場合はゼロ以外を返します。
  アセンブリを許可するように *ptr が変更された場合、C フラグも設定されます。
  呼び出しコードの最適化。

使用例:
 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 以降) の場合にのみ有効です。

これは、プリミティブを使用する ARMv3 の Linux で使用するためのswpものです。これをサポートしないようにするには、非常に古い ARM が必要です。スピンが失敗する原因となるのはデータ アボートまたは割り込みのみであるため、カーネルはこのアドレス~0xffff0fc0を監視し、データ アボートまたは割り込みが発生したときにユーザー空間 PCの修正を実行します。ARMv5 以前をサポートするすべてのユーザー空間ライブラリは、この機能を使用します。

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

于 2013-06-13T15:49:53.337 に答える