プログラミング言語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
文にはトランザクション例外指定子noexcept
/commit_on_escape
/cancel_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_safe
/transaction_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” であると推論される。
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
その他
- v1.1にあった「関数本体に対するトランザクション指定」、「式に対するトランザクション指定」は削除された。
- 「空のトランザクションが同期機構として機能するか?」という議論がなされているが、N3718時点では未決着。
関連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有無による整合チェックとして表現している。