知識マップ: スプリアスウェイクアップ ── 条件変数が「通知なしに目覚める」理由とWindowsでの正しい待ち方
記事「スプリアスウェイクアップ ── 条件変数が「通知なしに目覚める」理由とWindowsでの正しい待ち方」の主張を、概念と関係(エッジ)に分解した知識グラフの全体です。各関係には根拠・確認日・確度が付いています。
条件変数のwaitは、通知が来ていなくても戻ることがあります。Win32の公式ドキュメントは、スプリアスウェイクアップと、起こされたスレッドより先に別のスレッドが条件を消費する横取りの両方があると明記しています。3つのどの経路で戻ってきたかを呼び出し側は区別できないため、取れる戦略は「戻るたびに条件そのものを確認し、成立していなければもう一度眠る」しかありません。これはWindows固有の癖ではなく、POSIXもC++規格も同じで、ちょうど1つのスレッドだけを確実に起こす通知を厳密に実装すると条件変数のすべての操作に余分な同期コストがかかるという性能上の判断です。しかも横取りは実装を磨いても消せないため、待機側の再確認ループはどのみち必須になります。鏡像の問題が起こし損ねで、条件の確認と更新を同じロックの中で行えば防げます。
flowchart LR
accTitle: 条件変数のスプリアスウェイクアップの知識マップ
accDescr: waitから戻る3つの経路と呼び出し側が区別できないこと、性能とのトレードオフとして仕様が許した経緯、述語のwhileループによる対処、起こし損ねとの対比、PulseEventがカーネルAPCで通知を落とす問題を示す図
spurious_wakeup["スプリアスウェイクアップ"]
predicate_while_loop["述語のwhileループ再確認"]
win32_condition_variable["Win32の条件変数"]
stolen_wakeup["横取り(stolen wakeup)"]
critical_section["CRITICAL_SECTION"]
srw_lock["SRWロック(Slim Reader/Writer Lock)"]
race_condition["競合状態(race condition)"]
predicate_wait_overload["述語付きwait(lock, pred)"]
std_condition_variable["std::condition_variable"]
wait_on_address["WaitOnAddress"]
monitor_wait_pulse["Monitor.Wait / Pulse / PulseAll"]
lost_wakeup["起こし損ね(lost wakeup)"]
deadlock["デッドロック(deadlock)"]
pulseevent["PulseEvent"]
kernel_apc["カーネルモードAPC"]
win32_condition_variable -->|"原因になり得る"| spurious_wakeup
win32_condition_variable -->|"原因になり得る"| stolen_wakeup
win32_condition_variable -->|"利用する"| critical_section
win32_condition_variable -->|"利用する"| srw_lock
predicate_while_loop -->|"防止する"| race_condition
predicate_wait_overload -->|"実装を担う"| predicate_while_loop
std_condition_variable -->|"利用する"| predicate_wait_overload
std_condition_variable -->|"原因になり得る"| spurious_wakeup
wait_on_address -->|"原因になり得る"| spurious_wakeup
monitor_wait_pulse -->|"原因になり得る"| stolen_wakeup
monitor_wait_pulse -->|"前提とする"| predicate_while_loop
lost_wakeup -->|"原因になり得る"| deadlock
win32_condition_variable -->|"防止する"| lost_wakeup
spurious_wakeup -.->|"原因になり得る"| race_condition
pulseevent -->|"原因になり得る"| lost_wakeup
kernel_apc -.->|"原因になり得る"| lost_wakeup
win32_condition_variable -->|"の後継"| pulseevent
概念間の関係(全17件)
図と同じ関係を文章でも列挙します。表示している文と機械可読な意味データ(RDFa)は同じ要素に載っています。確度が「確立した関係」のものは直接の関係として、「条件付きの関係」のものは成立条件つきの言明(rdf:Statement)として表現しています。
- Win32の条件変数はスプリアスウェイクアップの原因になることがあります。
- Win32の条件変数は横取り(stolen wakeup)の原因になることがあります。
- Win32の条件変数はCRITICAL_SECTIONを利用します。
- Win32の条件変数はSRWロック(Slim Reader/Writer Lock)を利用します。
- 述語のwhileループ再確認は競合状態(race condition)を防ぎます。
- 述語付きwait(lock, pred)は述語のwhileループ再確認の実装を担います。
- std::condition_variableは述語付きwait(lock, pred)を利用します。
- std::condition_variableはスプリアスウェイクアップの原因になることがあります。
- WaitOnAddressはスプリアスウェイクアップの原因になることがあります。
- Monitor.Wait / Pulse / PulseAllは横取り(stolen wakeup)の原因になることがあります。
- Monitor.Wait / Pulse / PulseAllは述語のwhileループ再確認を前提とします。
- 起こし損ね(lost wakeup)はデッドロック(deadlock)の原因になることがあります。
- Win32の条件変数は起こし損ね(lost wakeup)を防ぎます。
- スプリアスウェイクアップは競合状態(race condition)の原因になることがあります。
- PulseEventは起こし損ね(lost wakeup)の原因になることがあります。
- カーネルモードAPCは起こし損ね(lost wakeup)の原因になることがあります。
- Win32の条件変数はPulseEventの後継に当たります。
主要概念の定義
機械可読データ
このデータセットについて
このページはサイトの知識グラフ(_data/knowledge/)から自動生成されています。誤りの指摘はお問い合わせからお願いします。