LoginSignup
4
3

More than 5 years have passed since last update.

Linuxでも__sync_bool_compare_and_swap_16がしたい!

Last updated at Posted at 2015-12-01

__sync_bool_compare_and_swap #とは

Cで計算結果をAtomicに代入したいとき、gccには__sync_bool_compare_and_swapという組み込み命令が用意されている。この関数の存在意義については説明しない(ググって)。

__sync_bool_compare_and_swap(ptr, cmp, swp)は第一引数で与えたポインタ(ptr)の先がcmpと等価なら、ptrの先にswpを代入する、という一連の動作をAtomicに行ってくれる。

実際はptrの大きさに応じて、__sync_bool_compare_and_swap_2, __sync_bool_compare_and_swap_4, __sync_bool_compare_and_swap_8などの命令の中からコンパイラがどれを使うかを判断している。

問題

ただ、8bytesの型にはlong longなどがあるので、8bytesまではサポートされているのだけれども、16bytesの型というのはあまりメジャーではない。ところが、どうしても16bytesのデータをAtomicに処理したい場合というのがあったりする(complex doubleとか)。

Mac付属のLLVM Clangだとデフォルトで__sync_bool_compare_and_swap_16が用意されているのだが、Ubuntuのgccでこれをコンパイルしようとすると、Undefined Referenceが出てしまう。

対処

前置きが長くなったが、これをどうにかするには、gccに次のオプションを指定するだけで良い。

gcc -mcx16

一応、gnuのドキュメントも引用しておこう。

-mcx16
This option enables GCC to generate CMPXCHG16B instructions. CMPXCHG16B allows for atomic operations on 128-bit double quadword (or oword) data types. This is useful for high-resolution counters that can be updated by multiple processors (or cores). This instruction is generated as part of atomic built-in functions: see __sync Builtins or __atomic Builtins for details.

使用例

例えば、次のように使うことができる。

atomic_add_complex_double.c
complex double tgt[1];
complex double tmp = hoge;
complex double new = fizz;
complex double diff = buzz;

while(!__sync_bool_compare_and_swap_16((__int128_t*)tgt, *((__int128_t*)&tmp), *((__int128_t*)&new))){tmp=*tgt; new=tmp+diff;}
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3