2009年5月26日

InitializeCriticalSectionEx

Team Japanの高橋さんの記事によると、Windows Vista(NT 6.0)以降ではInitializeCriticalSectionによる初期化ではリソースリークが発生するとのこと。

Team Japan » InitializeCriticalSectionEx

まぁそもそもマルチCPUではInitializeCriticalSectionAndSpinCountでスピンカウントの指定をしないとパフォーマンスに影響が出るらしいし、新しいOSではInitializeCriticalSectionExを呼び出しなさない、というのは判るのだが、もう少し互換性のある拡張はできないのかと。スピンカウントもどのくらいの値が適当なのかよくわからないし。

ちょうどいま流し読み中のWindowsデバッグの極意(Mario Hewardt、Daniel Pravat著/長尾高弘訳/アスキー・メディアワークス/ISBN978-4-04-867608-3)の"第10章 同期"でクリティカルセクションに触れています。以下引っ掛かる点を引用。
RTL_CRITICAL_SECTION.DebugInfo
クリティカルセクションに関する追加情報を格納する構造体で、これを格納するメモリはシステムにより確保される。(p.502)

RTL_CRITICAL_SECTION_DEBUG
RTL_CRITICAL_SECTION_DEBUGは主としてデバッグ用の情報を格納しているように見えるが、初期バージョンのWindowsでは、これがなければクリティカルセクションが使える状態だと見なされなかった。実際、オペレーティングシステムが初期化中にこの構造体のメモリを確保できなければ、APIは失敗していたのである。Windows Server 2003 SP1以降、このデバッグ情報がなくても、クリティカルセクションは機能するようになった。(p.504)

EnterCriticalSection
Windows 2000のEnterCriticalSection APIについては注意が必要だ。メモリの残量が少なくなったときにこれを呼び出すと、メモリ不足例外が投げられることがあるのだ。クリティカルセクションはイベントを使っており、EnterCriticalSection APIではこのイベントが初期化される。システムのメモリの残量が少なくなっていると、そのために例外が起きる。Windows 2000のもとでクリティカルセクションを信頼できる形で実行したければ、クリティカルセクションの初期化時にイベントを確保し、その後は例外を投げないInitializeCriticalSectionAndSpinCount APIを使うようにするとよい。(p.505)

追記: 高橋さん、フォローありがとうございます。

2 件のコメント:

高橋智宏 さんのコメント...

こんにちは。
修正版のコードに、各種宣言が欠けていたので、追加しました...。

高橋智宏 さんのコメント...

Vista以降には(実験的に)、クリティカルセクションを初期化する際に、スピンカウントを自動で調節するフラグが追加できるようになっています。が、あくまで実験的なフラグのようです。 それ以外は、パフォーマンスの検証によってスピンカウントの値を調節して設定するしかないですね。それか、0に設定しておくか。ただし、以下の書籍では 1,500 くらいが適当かも と解説しています。
http://www.amazon.co.jp/Concurrent-Programming-Windows-Microsoft-Development/dp/032143482X