C#にてクリティカルセクションのWindows API
を呼び出すとアプリが意図せずクラッシュすることがあります。特にフォームと閉じた時、などでクラッシュします。
CriticalSection系のWindows APIを呼び出す際に、CRITICAL_SECTION構造体が正しく定義されていないとこの問題が発生します。
CRITICAL_SECTION構造体を正しく定義します。
[DllImport("kernel32.dll")]
static extern void InitializeCriticalSection(out CRITICAL_SECTION lpCriticalSection);
[DllImport("kernel32.dll")]
static extern void EnterCriticalSection(ref CRITICAL_SECTION lpCriticalSection);
[DllImport("kernel32.dll")]
static extern void LeaveCriticalSection(ref CRITICAL_SECTION lpCriticalSection);
[StructLayout(LayoutKind.Sequential)]
public struct CRITICAL_SECTION{
public IntPtr DebugInfo;
public long LockCount;
public long RecursionCount;
public uint OwningThread;
public uint LockSemaphore;
public int Reserved;
}
CRITICAL_SECTION CriticalSection;
InitializeCriticalSection(out CriticalSection);
EnterCriticalSection(ref CriticalSection);
try {
(処理...)
}
finally {
LeaveCriticalSection(ref CriticalSection);
}
CRITICAL_SECTION構造体は変更不可のため、構造体を定義せずにメモリ領域のみを確保しても正しく動作します。
メモリの確保はMarshal.AllocHGlobal()メソッドを用います。
[DllImport("kernel32.dll")]
static extern void InitializeCriticalSection(IntPtr lpCriticalSection);
[DllImport("kernel32.dll")]
static extern void EnterCriticalSection(IntPtr lpCriticalSection);
[DllImport("kernel32.dll")]
static extern void LeaveCriticalSection(IntPtr lpCriticalSection);
IntPtr CriticalSection = Marshal.AllocHGlobal(40);
InitializeCriticalSection(CriticalSection );
EnterCriticalSection(CriticalSection );
try {
(処理...)
}
finally {
LeaveCriticalSection(CriticalSection );
}
Marshal.AllocHGlobal()に与えているサイズ40は以下のバイト数の和になります。
public struct CRITICAL_SECTION{ public IntPtr DebugInfo; //4(32bit) / 8(64bit) public long LockCount; //8 public long RecursionCount; //8 public uint OwningThread; //4 public uint LockSemaphore; //4 public int Reserved; //4 }
64ビットの場合、合計が36になります。(コードでは、構造体終端等を考慮して40バイトのメモリを確保しています。)