CriticalSectionクラス

提供: AB開発Wiki
移動先:案内検索

CriticalSectionクラスは、Windowsのクリティカルセクションをラップするクラスです。

クリティカルセクションは、スレッド間で同期を取るためのWin32オブジェクトの1つです。

クラスの機能

継承するインタフェース

メソッド

コンストラクタ

Sub CriticalSection()

デストラクタ

Sub ~CriticalSection()

Disposeを呼びます。

Dispose

クリティカルセクションオブジェクトを解放します。

Sub Dispose()

Enter

クリティカルセクションへ入ります。

Function Enter() As CriticalSectionLock
戻り値
CriticalSectionLockクラスのインスタンス

このメソッドは、クリティカルセクションの所有権を得るまで待機します。

まずはクリティカルセクションを使用せず、データに異常を来たす例です。

#console

#require <Classes/System/Threading/Thread.ab>

'共有資源
Type StringData
	str[16] As TCHAR
	len As SIZE_T
End Type

Dim data As StringData

Function TestProc(args As VoidPtr) As Long
	Do
		Dim buf[16] As TCHAR
		Dim i As Long

		Dim s = Nothing As String

		'異常を発生させやすくするため、わざと時間をかけて処理する
		With data
			For i = 0 To ELM(.len)
				buf[i] = .str[i]
				Sleep(60)
			Next

			s = New String(buf, .len As Long)
		End With
		Print s
		Sleep(0)
	Loop
End Function

Sub SetStringData(ByRef data As StringData)
	'出力文字列の変更
	With data
		lstrcpy(.str, ToTCStr("de"))
		.len = lstrlen(.str)
	End With
End Sub

With data
	lstrcpy(.str, ToTCStr("abc"))
	.len = lstrlen(.str)
End With

Dim t As Thread(AddressOf(TestProc),0)
t.Start()
Sleep(1000)

SetStringData(data)
Sleep(-1)

これを実行すると、例えば次のように出力されることがあります(常にこうなるとは限りません)。

abc
abc
ae
de
de
de

この場合では3行目の出力が異常なものになっています。これは、複数のスレッドが同時に変数strとlenを操作していることが原因です。

これをクリティカルセクションで保護すると次のようになります。

#console

#require <Classes/System/Threading/Thread.ab>
#require <Classes/ActiveBasic/Windows/CriticalSection.ab>

'共有資源
Type StringData
	str[16] As TCHAR
	len As SIZE_T
End Type

Dim data As StringData

Dim cs = New ActiveBasic.Windows.CriticalSection

Function TestProc(args As VoidPtr) As Long
	Do
		Dim buf[16] As TCHAR
		Dim i As Long

		Dim s = Nothing As String

		Dim lock = cs.Enter
		With data
			For i = 0 To ELM(.len)
				buf[i] = .str[i]
				Sleep(60)
			Next

			s = New String(buf, .len As Long)
		End With
		lock.Leave()

		Print s
		Sleep(0)
	Loop
End Function

Sub SetStringData(ByRef data As StringData)
	Dim lock = cs.Enter
	With data
		lstrcpy(.str, ToTCStr("de"))
		.len = lstrlen(.str)
	End With
	lock.Leave()
End Sub

With data
	lstrcpy(.str, ToTCStr("abc"))
	.len = lstrlen(.str)
End With

Dim t As Thread(AddressOf(TestProc),0)
t.Start()
Sleep(1000)

SetStringData(data)
Sleep(-1)

今度は行単位でデータの整合性が取れた出力になっています。

abc
abc
abc
de
de
de
de
de
de