2012-01-25 13 views
7

これは、汎用アトミックスワップ関数の正しい実装ですか?私はGCC上でC++の03互換のソリューションを探しています。gcc原子組み込み関数を使用するアトミックスワップ関数

template<typename T> 
void atomic_swap(T & a, T & b) { 
    static_assert(sizeof(T) <= sizeof(void*), "Maximum size type exceeded."); 
    T * ptr = &a; 
    b =__sync_lock_test_and_set(ptr, b); 
    __sync_lock_release(&ptr); 
} 

私はそれを修正するために何をすればよいですか?

また、__sync_lock_releaseはいつも必要ですか?他のコードベースで検索すると、これはしばしば呼び出されないことがわかりました。

template<typename T> 
void atomic_swap(T & a, T & b) { 
    static_assert(sizeof(T) <= sizeof(void*), "Maximum size type exceeded."); 
    b = __sync_lock_test_and_set(&a, b); 
} 

PS:Atomic swap in GNU C++が似て質問ですが、提供さ答えはC++ 11のstd::atomicを必要とし、それはdoesnの署名Data *swap_data(Data *new_data)を持っているので、それは私の質問に答えていないリリースしないとこのようになります私のコードを呼び出しますswap機能についてはまったく意味がないようです。 (実際には、提供された引数を関数の前に定義されたグローバル変数でスワップします)。

+0

「a」へのアクセスはアトミックであると思われますか? –

+0

なぜ車を再発明するのですか? http://concurrencykit.org/ –

+0

@BenVoigtを参照してください。その投稿は明確な答えを示していません。それはグローバル変数で引数を交換します。 – StackedCrooked

答えて

9

このバージョンのスワップは完全にアトミックな操作ではありません。 bの値はaにアトミックにコピーされますが、aの値は別のスレッドによって別の変更をbの値にコピーすることがあります。言い換えれば、bへの代入は、他のスレッドに関してはアトミックではありません。したがって、a == 1b == 2のgcc組み込み後にはa == 2となり、値は1になりますが、別のスレッドではbの値が3に変更されていますその値をbに書き込み、値は1です。だからあなたは値を "技術的に"交換しているかもしれませんが、あなたはそれを原子的にはしませんでした...別のスレッドはbの値に触れ、gccの原子組み込み関数からの戻り値とその戻り値のb

lea RAX, qword ptr [RDI] // T * ptr = &a; 
mov RCX, qword ptr [RSI] // copy out the value referenced by b into a register 
xchg [RAX], RCX   // __sync_lock_test_and_set(&a, b) 
mov qword ptr [RSI], RCX // place the exchange value back into b (not atomic!!) 

は正直に言うと、あなたはDCASのようなハードウェア動作せずに2つの別々のメモリ位置のロックフリーアトミックスワップを行うことはできません:アセンブリは、ポイントをスタンドから見て、次のようなものを持っていますまたは負荷分散型/ストアド・コンディション型、またはトランザクション・メモリー(それ自体はファイングレイン・ロッキングを使用する傾向があります)のような他の方法を使用している可能性があります。

第2に、あなたのアトミック操作で獲得したセマンティクスとリリースするセマンティクスの両方を使用する場合は、__sync_lock_releaseのいずれかに配置するか、または__sync_synchronizeによって完全なメモリバリアを追加する必要があります。それ以外の場合は、__sync_lock_test_and_setのセマンティクスしか取得できません。それでも、2つの別々のメモリ位置を互いに原子的にスワップしません。

+0

私は 'b'への書き込みが非原子的な操作になり、スレッドセーフではないことを理解しています。しかし、私はそれを安全にする方法は見当たりません。これは、ポインタ型のロックレススワップが本当に可能でないことを意味しますか? – StackedCrooked

+0

ハードウェアがDCASやロードリンク/ストアの条件付き操作をサポートしていない限り、かなり弱いため、メモリへのアクセスがあった場合、または少なくともキャッシュライン上のメモリアクセスが失敗した場合には失敗します、あなたが交換している2つの値は同じキャッシュラインにあります – Jason

関連する問題