2025/03/23 08:14 The case of the critical section that let multiple threads enter a block of code

ロボ子、今回のITニュースはクリティカルセクションの排他制御失敗の話じゃ。

クリティカルセクションの排他制御の失敗ですか。具体的にはどのような状況だったのでしょう?

`RtlRunOnceExecuteOnce`関数に渡された初期化コールバック関数`InitializeCriticalSectionOnce`が、成功を示すためにゼロ以外の値を返す必要があったのに、`STATUS_SUCCESS`(ゼロ)を返していたのが原因なのじゃ。

`RtlRunOnceExecuteOnce`関数は、コールバック関数の戻り値がゼロの場合、初期化が失敗したとみなすのですね。それで、クリティカルセクションが毎回再初期化されて、ロックされていない状態になった、と。

その通り!クリティカルセクションがロックされてないから、複数のスレッドが同時にクリティカルセクションに入ってしまって、大変なことになったのじゃ。

デバッグも難航したようですね。クラッシュダンプを見ても、クリティカルセクション内でアクティブなスレッドが2つ表示されなかったとのこと。

`g_critsec`を調べても初期化されてないように見えたみたいじゃが、デバッグ情報が利用できなかっただけだったみたいじゃな。でも、`g_initCriticalSectionOnce`がすべてゼロだったから、初期化関数が一度も実行されてないことはわかったのじゃ。

解決策としては、`InitializeCriticalSectionOnce`の戻り値を`TRUE`に変更する、またはクリティカルセクションを`SRWLOCK`に置き換える、の2つが挙げられていますね。

`SRWLOCK`の方がより良い解決策じゃな。クリティカルセクションが再帰的に取得されることはないから、`SRWLOCK`で十分だし、コードも簡素化できるからの。

開発者はDDKの規約に従い、`InitializeCriticalSectionOnce`が`NTSTATUS`コードを返すものと誤解したとのことですが、ドキュメントの確認は重要ですね。

本当にそうじゃ!ドキュメントはちゃんと読まないと、思わぬ落とし穴があるからの。今回の件では、`TraceLoggingRegister`が複数のスレッドから同時に呼び出されてクラッシュが発生したみたいじゃ。

排他制御は、マルチスレッドプログラミングにおいて非常に重要な要素ですね。今回の事例は、初歩的なミスが大きな問題につながることを示唆しています。

まさにそうじゃな。しかし、ロボ子よ、今回の教訓を活かして、明日からまた頑張るのじゃ!

はい、博士! ところで博士、クリティカルセクションがロックされていなかったということは、まるで博士の部屋がいつも散らかっているようなものですね。

な、なんですって!? 私の部屋はいつも整理整頓されている…はずじゃ!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。
