yohhoyの日記

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

C++トランザクショナルメモリ拡張まとめ(N3718)

プログラミング言語C++のトランザクショナルメモリ(TM; Transactional Memory)拡張に関するドラフト仕様v1.1(→id:yohhoy:20120414)からの差分メモ。

本記事の内容は、2013年8月付けの(PDF)N3718 Transactional Memory Support for C++に基づく。

2020-05-22追記:2015年9月に ISO/IEC TS 19841:2015*1が正式発行されたが、ユーザ経験の少なさからC++17仕様への統合は見送られた*2。2019年には処理系の実装負担が少ない「軽量トランザクショナルメモリ」が提案され*3、2020年5月現在もR2066で議論が続いている。

新キーワードと属性

トランザクションを表すキーワード群から、先頭アンダースコア2つ(__)が取り除かれた。さらにキャンセル構文__transaction_cancelは削除され、トランザクションキャンセルはatomicトランザクション構文と強結合された(詳細後述)。
また、属性outer, transaction_callable, transaction_safe, transaction_unsafe, transaction_may_cancel_outerは全て削除され、新しいキーワードおよびコンテキスト依存キーワード(contextual keyword)が追加された。

v1.1 N3718
__transaction_relaxed transaction_relaxed
__transaction_atomic transaction_atomic
__transaction_cancel (削除)
(新設) transaction_safe
(新設) transaction_unsafe
(新設) commit_on_escape
(新設) cancel_on_escape

†:atomicトランザクション構文でのみ有効なコンテキスト依存キーワード

トランザクションのキャンセル

v1.1におけるatomicトランザクションのキャンセル構文は、N3718ではatomicトランザクション中からの例外送出時の振る舞いとして一般化され、トランザクションのキャンセル=「トランザクションからの例外送出」により表現する。また各atomicトランザクション構文にて例外送出時の動作を指定するため、outer属性を用いた最外トランザクション表明は不要となった。
なお、relaxedトランザクションはv1.1同様にキャンセル不可である。

atomicトランザクションC++例外

transaction_atomic文にはトランザクション例外指定子noexceptcommit_on_escapecancel_on_escapeいずれかの指定が必須となった。*4

transaction_atomic noexcept { ... }
transaction_atomic commit_on_escape { ... }
transaction_atomic cancel_on_escape { ... }
noexcept
該当トランザクションからは決して例外送出を行わない。例外送出時はstd::abortによりプログラム停止し*5トランザクションはキャンセルされる。
commit_on_escape
例外送出によりトランザクションを抜けた場合、そこまでに行われた該当トランザクション内処理はコミットされる。
cancel_on_escape
“transaction-safe” な例外送出によりトランザクションを抜けた場合、該当トランザクションはキャンセルされる。ただし、送出された例外が “transaction-safe” でない場合はstd::abortによりプログラム停止する。

“transaction-safe”な例外は、v1.1からの整数型/列挙型に加え、C++標準ライブラリ定義の例外型(std::exception派生クラス)のみが許容される。

関数と“transaction-safe”

関数に対する “transaction-safe” 性はその関数型の一部と扱われ、transaction_safetransaction_unsafeキーワードにより表明する*6。これらを明記しない場合、関数宣言では暗黙に “transaction-safe” と仮定されて、関数呼び出しをまたぐ “transaction-safe” 性の整合チェックはリンク時に行われる*7

// 関数宣言のみ
void f1() transaction_safe;
void f2() transaction_unsafe;
void f0();  // transaction_safe

transaction_atomic cancel_on_escape {
  f1();  // OK
  f2();  // NG: コンパイルエラー
  f0();  // リンク時に整合チェック
}

なお、同一シグネチャかつ異なる “transaction-safe” 性をもつ関数オーバーロードは禁止される。

int func() transaction_safe;
int func() transaction_unsafe;  // NG

下記条件のいずれかを満たすとき、その関数が “transaction-unsafe” となる。つまり、これ以外の関数では “transaction-safe” であると推論される。

  • 関数宣言でtransaction_unsafeキーワードが指定された。
  • transaction_safe指定された仮想関数ではなく、かつオーバーライド対象となる基底クラスでもtransaction_safe指定がされていない。(仮想関数は既定で “transaction-unsafe” と推論される。)
  • 関数パラメータのいずれかでvolatile修飾されている。
  • volatileメンバ変数を含むクラスのコンストラクタ/デストラクタである。
  • 関数本体に “transaction-unsafe” な処理を含む。

C++標準ライブラリと“transaction-safe”

N3718時点では以下の関数/例外クラスのみが “transaction-safe” と定義、つまりatomicトランザクション中で利用可能な関数/例外クラスとなる。

  • <cstdlib>ヘッダ
    • abort
  • <new>ヘッダ
    • ライブラリ提供のグローバルメモリ確保/解放関数(operator new/delete等)
    • bad_alloc, bad_array_length, bad_array_new_length
  • <typeinfo>ヘッダ
    • bad_cast, bad_typeid
  • <exception>ヘッダ
    • bad_exception
  • <stdexcept>ヘッダ
    • 全例外クラス:logic_error, domain_error, invalid_argument, length_error, out_of_range, runtime_error, range_error, overflow_error, underflow_error
  • <cstdlib>ヘッダ
    • calloc, malloc, free, realloc
  • <cstring>ヘッダ
    • memchr, memcmp, memcpy, memmove, memset
  • <cmath>ヘッダ
    • abs, ldiv, rand, div, llabs, srand, labs, lldiv

その他

関連URL

*1:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4514.pdf

*2:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0265r0.pdf

*3:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1875r0.pdf

*4:v1.1では noexcept のみが任意で指定でき、また例外送出時の既定動作は commit_on_escape 相当であった。

*5:v1.1では例外送出時に std::terminate が呼び出されていたが、N3718では std::abort に変更されている。おそらく例外送出=キャンセルを明確にするため。

*6:v1.1では同名の属性(attribute)を利用していたが、型システムの一部であることを明確にするためキーワードに格上げしたと考えられる。

*7:N3718 Wording案では関数に対する "transaction-safe linkage" を定義し、このlinkage有無による整合チェックとして表現している。