UWSCで排他制御

いろいろ検討したけど、CreateMutexが良い模様。
以下は、検討したスクリプト




SemaphoreとCriticalSectionは面倒になった。
ただの排他なら、Mutexで良いことがわかった。
パラメーターでの排他は、アトミックじゃないことはわかってるけど、大きく違うなら優位かと思ったのだけど、、、。
今後必要になったら、Mutex部分のみ切り出せばOK。

OPTION EXPLICIT

CONST num = 16
PUBLIC _bThread[num]
DIM i
Mutex.Init(4)
FOR i = 1 TO num
	_bThread[i] = TRUE
	THREAD TestThread(i)
NEXT
DIM loop = TRUE
WHILE loop
	loop = FALSE
	FOR i = 1 TO num
		loop = loop OR _bThread[i]
		IF loop THEN BREAK
	NEXT
	SLEEP(1)
WEND
Mutex.Release()


FUNCTION Log(msg, t=0)
	DIM n = GETTIME() * 1000 + G_TIME_ZZ
	DIM buf = G_TIME_NN2 + ":" + G_TIME_SS2 + "." + G_TIME_ZZ2 + " " + msg
	IF t > 0 THEN buf = buf + "(" + (n - t) + ")"
	PRINT buf
	RESULT = n
FEND

PROCEDURE TestThread(id)
	DIM s = Log("TestThread init " + id)
	Log("TestThread start " + id + " " + Mutex.Lock(id))
	SLEEP(0.1)
	Log("TestThread end " + id, s)
	Log("TestThread fin " + id + " " + Mutex.Unlock(id), s)
	_bThread[id] = FALSE
FEND


MODULE Mutex
	CONST _wait = 0.001
	// ロック機構は、Mutex/Semaphore/Event/CriticalSection等がある
	PUBLIC _mode = 1
	DIM _id = 0

	DIM _handle
	DEF_DLL CloseHandle(dword): bool: kernel32.dll
	DEF_DLL GetLastError(): dword: kernel32.dll
	DEF_DLL WaitForSingleObject(dword, dword): dword: kernel32.dll
	CONST WAIT_FAILED = $FFFFFFFF
	CONST WAIT_OBJECT_0 = 0
	CONST WAIT_ABANDONED = $80
	CONST WAIT_TIMEOUT = 258

	// Mutex用
	DEF_DLL CreateMutexA(dword, bool, string): dword: kernel32.dll
	DEF_DLL ReleaseMutex(dword): bool: kernel32.dll

	// Event用
	DEF_DLL CreateEventA(dword, bool, bool, string): dword: kernel32.dll
	DEF_DLL SetEvent(dword): bool: kernel32.dll

	// CriticalSection、、、はちょっと断念


	// 3.812
	PROCEDURE InitPara()
		_mode = 1
		_id = 0
	FEND
	FUNCTION TryLockPara(id)
		RESULT = FALSE
		IFB _id = 0 THEN
			_id = id
			SLEEP(_wait)
			RESULT = (_id = id)
		ENDIF
	FEND
	FUNCTION UnlockPara(id)
		RESULT = (_id = id)
		IF RESULT THEN _id = 0
	FEND
	FUNCTION ReleasePara()
		RESULT = TRUE
	FEND

	// 優位差は見られない
	PROCEDURE InitMutex()
		_mode = 2
		_id = 0
		_handle = CreateMutexA(NULL, FALSE, NULL)
	FEND
	FUNCTION TryLockMutex(id)
		RESULT = FALSE
		DIM ret = WaitForSingleObject(_handle, 0)
		IFB ret = WAIT_OBJECT_0 THEN
			_id = id
			RESULT = TRUE
		ENDIF
	FEND
	FUNCTION UnlockMutex(id)
		RESULT = (_id = id)
		IFB RESULT THEN
			IF !ReleaseMutex(_handle) THEN Log("UnlockMutex ReleaseMutex Error " + GetLastError())
			_id = 0
		ENDIF
	FEND
	FUNCTION CloseMutex()
		RESULT = CloseHandle(_handle)
		IF !RESULT THEN Log("CloseMutex CloseHandle Error " + GetLastError())
	FEND

	PROCEDURE InitSemaphore()
		_mode = 3
		_id = 0
	FEND
	FUNCTION TryLockSemaphore(id)
		RESULT = FALSE
		SLEEP(_wait)
		IFB _id = 0 THEN
			_id = id
			SLEEP(_wait)
			IFB _id = id THEN
				RESULT = TRUE
			ENDIF
		ENDIF
	FEND
	FUNCTION UnlockSemaphore(id)
		RESULT = (_id = id)
		IF RESULT THEN _id = 0
	FEND
	FUNCTION ReleaseSemaphore()
		RESULT = TRUE
	FEND

	// 優位差は見られない
	PROCEDURE InitEvent()
		_mode = 4
		_id = 0
		_handle = CreateEventA(NULL, FALSE, TRUE, NULL)
	FEND
	FUNCTION TryLockEvent(id)
		RESULT = FALSE
		DIM ret = WaitForSingleObject(_handle, 0)
		IFB ret = WAIT_OBJECT_0 THEN
			_id = id
			RESULT = TRUE
		ENDIF
	FEND
	FUNCTION UnlockEvent(id)
		RESULT = (_id = id)
		IFB RESULT THEN
			IF !SetEvent(_handle) THEN Log("UnlockEvent SetEvent Error " + GetLastError())
			_id = 0
		ENDIF
	FEND
	FUNCTION ReleaseEvent()
		RESULT = CloseHandle(_handle)
		IF !RESULT THEN Log("ReleaseEvent CloseHandle Error " + GetLastError())
	FEND

	PROCEDURE InitCriticalSection()
		_mode = 5
		_id = 0
	FEND
	FUNCTION TryLockCriticalSection(id)
		RESULT = FALSE
		SLEEP(_wait)
		IFB _id = 0 THEN
			_id = id
			SLEEP(_wait)
			IFB _id = id THEN
				RESULT = TRUE
			ENDIF
		ENDIF
	FEND
	FUNCTION UnlockCriticalSection(id)
		RESULT = (_id = id)
		IF RESULT THEN _id = 0
	FEND
	FUNCTION ReleaseCriticalSection()
		RESULT = TRUE
	FEND


	PROCEDURE Init(mode)
		SELECT mode
			CASE 1
				InitPara()
			CASE 2
				InitMutex()
			CASE 3
				InitSemaphore()
			CASE 4
				InitEvent()
			CASE 5
				InitCriticalSection()
		SELEND
	FEND
	FUNCTION TryLock(id)
		SELECT _mode
			CASE 1
				RESULT = TryLockPara(id)
			CASE 2
				RESULT = TryLockMutex(id)
			CASE 3
				RESULT = TryLockSemaphore(id)
			CASE 4
				RESULT = TryLockEvent(id)
			CASE 5
				RESULT = TryLockCriticalSection(id)
		SELEND
	FEND
	FUNCTION Lock(id)
		RESULT = TRUE
		WHILE !TryLock(id)
			SLEEP(_wait)
		WEND
	FEND
	FUNCTION Unlock(id)
		SELECT _mode
			CASE 1
				RESULT = UnlockPara(id)
			CASE 2
				RESULT = UnlockMutex(id)
			CASE 3
				RESULT = UnlockSemaphore(id)
			CASE 4
				RESULT = UnlockEvent(id)
			CASE 5
				RESULT = UnlockCriticalSection(id)
		SELEND
	FEND
	FUNCTION Release()
		SELECT _mode
			CASE 1
				RESULT = ReleasePara()
			CASE 2
				RESULT = CloseMutex()
			CASE 3
				RESULT = ReleaseSemaphore()
			CASE 4
				RESULT = ReleaseEvent()
			CASE 5
				RESULT = ReleaseCriticalSection()
		SELEND
	FEND
ENDMODULE