現代のすべてのOSは今日、いくつかのアトミック操作を提供しています。
Interlocked*
APIがあります<machine/atomic.h>
があります<atomic.h>
があります<libkern/OSAtomic.h>
がありますLinuxでそのようなことはありますか?
問題点:
__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をサポートする何かを見たいです。
プロジェクトはこれを使用しています:
http://packages.debian.org/source/sid/libatomic-ops
CASなどの単純な操作が必要な場合は、カーネルからArch固有の実装を使用するだけで、autotools/cmakeを使用してユーザー空間でArchチェックを実行できませんか?ライセンスに関しては、カーネルはGPLですが、これらの操作のインラインアセンブリはIntel/AMDによって提供されるのではなく、カーネルにライセンスがあるというのは間違いないと思います。それらはカーネルソースで簡単にアクセスできる形式になっています。
C&C++の最近の標準(2011年以降)では、アトミック操作が指定されています。
stdatomic.h
std::atomic
とにかく、ご使用のプラットフォームまたはコンパイラーがこれらの新しいヘッダーと機能をサポートしていない場合があります。
くそーGCCプリミティブを提案するつもりだったのですが、それらは立ち入り禁止だと言いました。 :-)
その場合、#ifdef
気にするアーキテクチャ/コンパイラの組み合わせごとに、インラインasmをコーディングします。そして、__GNUC__
または同様のマクロがあり、GCCプリミティブが使用可能な場合はそれを使用します。これらを使用する方がはるかに適切だと感じているためです。 :-)
多くの重複があり、正確性を確認するのは難しいかもしれませんが、これは多くのプロジェクトがこれを行う方法であるようであり、私はそれで良い結果を得ました。
過去に私を苦しめたいくつかの落とし穴:GCCを使用するときは、「asm volatile
"および"memory"
および"cc"
など.
ARMアトミック操作をサポートするためのGCCのパッチがあります。Intelでは役に立ちませんが、コードを調べることができます-古いARMアーキテクチャ、および新しいアーキテクチャには命令が組み込まれているため、動作するものをビルドできるはずです。
Boostは非侵入型のライセンスを持ち、他のフレームワークは既にターゲットプラットフォームでサポートされている限り、移植可能なアトミックカウンターを提供しています。
サードパーティのライブラリは私たちに適しています。そして、奇妙な理由で会社がそれらを使用することを禁じている場合でも、あなたが探しているものを実装するためにそれらがどのように進むかを見ることができます(ライセンスがあなたの使用を許可する限り)。
__sync*
は確かにIntelコンパイラによってサポートされています(GCCはそこからこれらのビルドインを採用しているため)。最初の段落を読む このページ 。 「 Intel®C++ Compiler for Linux * Intrinsics Reference 」、198ページも参照してください。これは2006に由来し、作成されたものを正確に説明しています。 -ins。
ARMサポートについては、古いARM CPUの場合:ユーザー空間で完全に実行することはできませんが、カーネル領域で実行できます(操作中の割り込みを無効にすることにより) 、そして私はどこかでそれがかなり長い間サポートされていると読んだと思います。
this PHP bug 、2011-10-08日付、__sync_*
は失敗するだけです
したがって、GCC> 4.3(および4.7が現在のもの)であれば、ARMv6以降では問題はないはずです。 Linux向けにコンパイルしている限り、ARMv5でも問題はないはずです。
私は最近そのようなことを実装しましたが、あなたと同じ困難に直面しました。私の解決策は基本的に次のとおりでした:
__asm__
_を使用してcmpxch
のようなものを実装するだけです(ARMはそれよりも少し複雑です)。 sizeof(int)
のような1つの可能なサイズに対してそれを行ってください。inline
関数を使用して、1つまたは2つのプリミティブの上に他のすべての機能を実装します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);
kernel_user_helpers.txt または entry-arm.c を参照して、__kuser_cmpxchg
。他のARM Linuxバージョン、
場所: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;
}
注:
これは、swp
プリミティブを使用するARMv3を搭載したLinuxで使用するためのものです。これをサポートしないためには、非常に古いARMが必要です。data abortまたはinterruptスピンが失敗する可能性があるため、カーネルはこのアドレス〜0xffff0fc0を監視し、ユーザースペースPC
data abortまたはinterruptが発生した場合の修正ARMv5以前をサポートするすべてのユーザー空間ライブラリは、この機能を使用します。
たとえば、QtConcurrentはこれを使用します。