yohhoyの日記

技術的メモをしていきたい日記

C++トランザクショナルメモリ拡張まとめ(ドラフト仕様v1.1)

プログラミング言語C++のトランザクショナルメモリ(TM; Transactional Memory)拡張に関するざっくりまとめメモ。

2013-10-05追記:本記事の内容はN3718にてアップデートされている。→id:yohhoy:20131005

本記事の内容は、2012年4月現在の最新ドラフト仕様 “Draft Specification of Transactional Language Constructs for C++, Version 1.1”(→id:yohhoy:20120413)に基づく。

超要約:Isolation と Atomicity を保証し、かつ Composable なトランザクション機能を提供する。

概要

C++トランザクショナルメモリ拡張が提供する機能の概要は下記の通り。

新キーワードと属性

C++トランザクショナルメモリ拡張の仕様では、3つのキーワードと5つの属性が新たに導入される*1

// 新キーワード
__transaction_relaxed
__transaction_atomic
__transaction_cancel
// 属性(コメントはアノテート対象)
outer  // atomicトランザクション, キャンセル文
transaction_callable          // 関数, クラス
transaction_safe              // 関数, クラス
transaction_unsafe            // 関数, クラス
transaction_may_cancel_outer  // 関数

relaxedトランザクション

relaxedトランザクションの指定はキーワード__transaction_relaxedを用いる。

// 複合文
__transaction_relaxed {
  //...
}

// 関数
void f() __transaction_relaxed
{
  //...
}

// 式
T v = __transaction_relaxed (/*...*/);

relaxedトランザクション内から呼び出される関数はtransaction_callable属性でアノテートできる(しなくてもよい)。relaxedトランザクション実装のパフォーマンス向上を目的としており、関数アノテートはプログラムの意味には影響しない。

[[transaction_callable]] void h();
__transaction_relaxed { h(); }

atomicトランザクション

atomicトランザクションの指定はキーワード__transaction_atomicを用いる。

// 複合文
__transaction_atomic {
  //...
}

// 関数
void f() __transaction_atomic
{
  //...
}

// 式
T v = __transaction_atomic (/*...*/);

トランザクション入れ子とされない最外トランザクションであることを強制するには、atomicトランザクションに対してouter属性でアノテートする。

void f0()
{
  __transaction_atomic { /*...*/ }
}
void f1()
{
  __transaction_atomic [[outer]] { /*...*/ }
}

__transaction_atomic { f0(); }  // OK: well-formed
__transaction_atomic { f1(); }  // NG: ill-formed

関数が安全である/安全でないと指定するには、関数に対してtransaction_safetransaction_unsafe属性でアノテートする。

int x, y, z;  // 組み込み型
[[transaction_safe]] int f0();   // 安全な関数
[[transaction_unsafe]] int f1(); // 安全でない関数

__transaction_atomic {
  ++x;       // OK: well-formed
  y = f0();  // OK: well-formed
  z = f1();  // NG: ill-formed
}

クラスに対してアノテートした場合は、同クラスの全メンバ関数に対して個々にアノテートしたのと等価。さらにメンバ関数をアノテートして属性を上書きすることも出来る。

class C [[transaction_safe]] {
  void mf1();         // transaction_safe
  virtual void mf2(); // transaction_safe
  [[transaction_unsafe]] void mf3(); // transaction_unsafe
};

キャンセル文

キャンセル文はキーワード__transaction_cancelを用いる。

__transaction_atomic {
  //...
  if (/*...*/)
    __transanction_cancel;  // cancel文
  //...
  if (/*...*/)
    __transaction_cancel throw 42;  // cancel-and-thorw文
}

最外トランザクションをキャンセルするには、キャンセル文に対してouter属性でアノテートする。

__transaction_atomic [[outer]] {  // トランザクションT1
  // 処理1
  __transaction_atomic {          // トランザクションT2
    // 処理2
    if (/*...*/)
      __transaction_cancel;            // T2(処理2)をキャンセル
    if (/*...*/)
      __transaction_cancel [[outer]];  // T1(処理1,処理2)をキャンセル
  }
}

関数中で__transaction_cancel [[outer]]を行う可能性があることを表明するには、関数に対してtransaction_may_cancel_outer属性でアノテートする。

[[transaction_may_cancel_outer]] void f()
{
  //...
  if (/*...*/)
    __transaction_cancel [[outer]];
}

__transaction_atomic [[outer]] {
  //...
  __transaction_atomic { f(); }
}

outerアノテートされないキャンセル文は、必ずatomicトランザクションのレキシカル・スコープ内に無ければならない。outerアノテートされたキャンセル文は、outerアノテートされたatomicトランザクションのレキシカル・スコープ内、またはtransaction_may_cancel_outerアノテートされた関数内のいずれかに無ければならない。


関連URL

*1:属性(attribute)はC++11で導入された構文。例:outer属性ならば [[outer]] と記述する。

*2:スライド資料はドラフト仕様v1.0に基づいているため、v1.1とはトランザクション指定のキーワード名称が異なる。__transaction → __transaction_atomic、__transaction [[relaxed]] → __transaction_relaxed と変更された。