「基本的なプリミティブ」の項では、
移植性や実行効率を高めるため、
共有メモリ向けプリミティブとその記述を示した。
一方、プリミティブの普及を図るには既存のシステムでもできるだけ利用可能であることが望ましい。
そこでプリミティブを少し変更し、
GCCの拡張機能による実現を行った。
ここではこの「マクロ版プリミティブ」について詳しく解説する。
atomic_read(),atomic_write(),atomic_swap(),cas()に関しては、
同期変数の型ごとにそれぞれ異なるプリミティブを用意する。
これはGCCの拡張機能の範囲内で扱う以上、
型付けの結果で生成するコードを切り替えることができないためである。
また、atomic_write に関しては、基本的なプリミティブの項では式として扱ったが、
マクロ版では文として扱うことにした。
以下、atomic_write,atomic_swap,cas についても同様に、 char,short,int,long,long long,float,double,void * の型ごとについて プリミティブを用意する。
メモリバリアプリミティブについては、対象となる範囲指定を記述できないものとした。 不定長のリストが構文拡張以外では扱いにくいこと、 範囲指定を有効利用するにはコンパイラで最適化などにこれを生かす必要があるが、 コンパイラを手に入れない以上それが望めないことがその理由である。
membar()文の代わりに、 ssbar(),slbar(),sabar(),lsbar(),llbar(),labar(),asbar(),albar(),aabar() というプリミティブの文を用意し、 同期アクセスの完了順序を保証する範囲ごとに使いわけることにする。 例えば直前のストアと直後のストア間のアクセス完了順序を保証するならssbar()、 直前のストアと直後のロード間ならslbar()、 その両方についてならsabar()というふうに、 プリミティブを使い分けることにする。
また、start_access(),finish_access()に関しては、 直前の同期変数へのアクセスは自動的に見つけられないので、 start_access_after_lock(),start_access_after_read(),start_access_after_write(), finish_access_before_unlock(),finish_access_before_read(),finish_access_after_write() などのプリミティブを用意する。 直前の同期変数へのアクセスの仕方(loadかstore、もしくはその両方)によって、 start_read_after_lock(),start_write_after_lock(),start_access_after_lock() のようにプリミティブを用意し、 適宜使い分けるようにする。
以下同様に、プリミティブ名の先頭2文字によって、 s = ストア、l = ロード、a = ストアとロード両方、 という様に区別されたプリミティブを用意する。
以下同様に、access,read,write によって メモリバリアの対象となる、直後の同期変数へのアクセスの方法を指定し、 after_lock,after_read,after_write によって、 直前の同期変数へのアクセス方法を指定する。
以下同様に、access,read,write によって 直前の同期変数へのアクセスの方法を指定し、 before_unlock,before_read,before_write によって、 メモリバリアの対象となる、直後の同期変数へのアクセス方法を指定する。