UWSCのスレッドは自在に操れない

以前、以下のような記事を書いた。
junjun777.hatenablog.com


先日、とらさんから強制終了できないか、と相談を受けて機能追加してみたのだけど、、、。
ダメだった。


ま、スレッドを強制終了なんてしちゃいけないんですよ!
以下、その詳細である。



スクリプト

まあさ、TerminateThreadすればいいじゃん、って思うでしょ。
で、さくっと書いてみるわけです。
Thread.uws

OPTION EXPLICIT

IFB GET_UWSC_NAME = "Thread.uws" THEN
	// CPU情報取得
	DIM cpus, packs = Thread.GetCpuInfo(cpus)
	DIM i
	FOR i = 0 TO LENGTH(cpus) - 1
		PRINT "cpu" + i + " core" + cpus[i]
	NEXT
	FOR i = 0 TO LENGTH(packs) - 1
		PRINT "cpu" + i + " same package core" + packs[i]
	NEXT

	// プロセスのAffinityMask取得
	Thread.GetAffinityMask(i)
	PRINT "process affinity mask:0x" + REPLACE(FORMAT(i, 8, -1), " ", "0")

	// スレッド操作用に選択項目定義
	FOR i = 0 TO LENGTH(cpus) - 1
		cpus[i] = "cpu" + i
	NEXT
	i = LENGTH(cpus) + 4
	RESIZE(cpus, i)
	cpus[i] = "End"
	cpus[i-1] = "Terminate"
	cpus[i-2] = "Resume"
	cpus[i-3] = "Suspend"
	cpus[i-4] = "free cpu"

	// スレッド操作。ビジーループなので、タスクマネージャーと見比べてね
	DIM name = "sample", loop = TRUE
	Thread.Start(name, "SampleFunc(<#DBL>" + name + "<#DBL>)")
	WHILE loop
		i = SLCTBOX(SLCT_STR, 0, "control thread", cpus)
		SELECT i
		CASE -1, "End"
			loop = FALSE
		CASE "Terminate"
			PRINT i + ":" + Thread.Terminate(name)	// 強制終了:失敗(0)、成功(0以外)
		CASE "Suspend"
			PRINT i + ":" + Thread.Suspend(name)	// 一時停止:失敗(-1)、成功(前回停止カウンター)
		CASE "Resume"
			PRINT i + ":" + Thread.Resume(name)		// 再開:失敗(-1)、成功(前回停止カウンター)
		CASE "free cpu"
			PRINT i + ":" + Thread.SetAffinityMask(name)	// 設定:失敗(0)、成功(前回マスク)
		DEFAULT
			i = VAL(COPY(i, 4))
			PRINT "cpu" + i + " set:" + Thread.SetAffinityMask(name, Thread.MakeAffinityMask(i))
		SELEND
	WEND
	Thread.Stop(name)

	Thread.Dispose()	// スクリプトの最後に破棄した方が良いかも
ENDIF

// スレッド関数サンプル
PROCEDURE SampleFunc(name)		// Threadにつけた名前は必ず必要
	WHILE Thread.IsLoop(name)	// 無限ループスレッドは、条件をIsLoopに従う
		//GETTIME()
		//PRINT G_TIME_HH2 + ":" + G_TIME_NN2 + ":" + G_TIME_SS2
		//SLEEP(1)
	WEND
	MSGBOX("Thread Exit?")
	Thread.Exit(name)			// 終了前に必ずExitを呼ぶ
FEND


MODULE Thread
	DEF_DLL GetCurrentThreadId(): DWORD: kernel32
	DEF_DLL OpenThread(DWORD,BOOL,DWORD): DWORD: kernel32
	DEF_DLL CloseHandle(DWORD): BOOL: kernel32
	DEF_DLL SuspendThread(DWORD): DWORD: kernel32
	DEF_DLL ResumeThread(DWORD): DWORD: kernel32
	DEF_DLL TerminateThread(DWORD,DWORD): long: kernel32
	DEF_DLL GetProcessAffinityMask(DWORD,var DWORD,var DWORD): BOOL: kernel32
	DEF_DLL SetProcessAffinityMask(DWORD,DWORD): BOOL: kernel32
	DEF_DLL SetThreadAffinityMask(DWORD,DWORD): DWORD: kernel32

	HASHTBL _loops
	HASHTBL _threads
	DIM _hProcess

	PROCEDURE Thread
		DEF_DLL GetCurrentProcess(): DWORD: kernel32
		_hProcess = GetCurrentProcess()
	FEND

	PROCEDURE Start(name, func, op=EMPTY)
		_loops[name] = TRUE
		THREAD PrivateFunc(name, func, op)
	FEND
	FUNCTION PrivateFunc(name, func, op)
		_threads[name] = OpenThread($63, FALSE, GetCurrentThreadId())
		RESULT = EVAL(func)
	FEND
	FUNCTION Exit(name)
		RESULT = _threads[name, HASH_EXISTS]
		IFB RESULT THEN
			CloseHandle(_threads[name])
			RESULT = _threads[name, HASH_REMOVE]
		ENDIF
	FEND
	FUNCTION Stop(name, max=0, bResume=TRUE)
		_loops[name] = FALSE
		// 終了待ち
		DIM res = 1, counter = 0
		WHILE _threads[name, HASH_EXISTS]
			IF res > 0 AND bResume THEN res = this.Resume(name)
			SLEEP(0.01)
			IFB max > 0 THEN
				counter = counter + 1
				IF counter > max THEN BREAK
			ENDIF
		WEND
		RESULT = _loops[name, HASH_REMOVE]
	FEND
	FUNCTION IsLoop(name)
		RESULT = FALSE
		IF _loops[name, HASH_EXISTS] THEN RESULT = _loops[name]
	FEND
	FUNCTION Suspend(name)
		RESULT = -1
		IF _threads[name, HASH_EXISTS] THEN RESULT = SuspendThread(_threads[name])
	FEND
	FUNCTION Resume(name)
		RESULT = -1
		IF _threads[name, HASH_EXISTS] THEN RESULT = ResumeThread(_threads[name])
	FEND
	FUNCTION Terminate(name, exitCode=-1)
		RESULT = 0
		IF _threads[name, HASH_EXISTS] THEN RESULT = TerminateThread(_threads[name], exitCode)
		Exit(name)
	FEND
	FUNCTION Dispose()
		RESULT = LENGTH(_threads)
		DIM i, name
		FOR i = 0 TO RESULT - 1
			name = _threads[i, HASH_KEY]
			this.Stop(name)
		NEXT
		_threads = HASH_REMOVEALL
		_loops = HASH_REMOVEALL
	FEND

	FUNCTION GetAffinityMask(var mask)
		IFB !GetProcessAffinityMask(_hProcess, mask, RESULT) THEN
			RESULT = 0
		ENDIF
	FEND
	FUNCTION SetAffinityMask(name=EMPTY, mask=0)
		IF mask = 0 THEN this.GetAffinityMask(mask)
		IFB name = EMPTY THEN
			RESULT = SetProcessAffinityMask(_hProcess, mask)
		ELSEIF _threads[name, HASH_EXISTS] THEN
			RESULT = SetThreadAffinityMask(_threads[name], mask)
		ELSE
			RESULT = FALSE
		ENDIF
	FEND
	FUNCTION MakeAffinityMask(no)
		RESULT = POWER(2, no)
	FEND

	FUNCTION GetCpuInfo(var rcpus)
		DEF_DLL GetLogicalProcessorInformation(var DWORD[], var DWORD): BOOL: kernel32
		DIM infoLen = 0, res
		TRY
			GetLogicalProcessorInformation(NULL, infoLen)
			res = (infoLen > 0)
		EXCEPT
			res = FALSE
		ENDTRY
		HASHTBL cpus
		HASHTBL cores
		IFB res THEN
			DIM infos[infoLen / 4]
			res = GetLogicalProcessorInformation(infos, infoLen)
			DIM i, core = 0, no = 0, set
			FOR i = 1 TO LENGTH(infos) - 6 STEP 6
				SELECT infos[i]
				CASE 0
					no = 0
					WHILE infos[i-1]
						IF infos[i-1] MOD 2 THEN cpus[no] = core
						infos[i-1] = INT(infos[i-1] / 2)
						no = no + 1
					WEND
					core = core + 1
				CASE 1
					no = 0
					set = -1
					WHILE infos[i-1]
						IFB infos[i-1] MOD 2 THEN
							IF set = -1 THEN set = no
							cores[no] = cpus[set]
						ENDIF
						infos[i-1] = INT(infos[i-1] / 2)
						no = no + 1
					WEND
				SELEND
			NEXT
		ENDIF
		IFB LENGTH(cpus) THEN
			rcpus = SAFEARRAY(0, LENGTH(cpus) - 1)
			FOR res = 0 TO LENGTH(cpus) - 1
				rcpus[res] = cpus[res]
			NEXT
		ELSE
			rcpus = SPLIT(EMPTY)
		ENDIF
		IFB LENGTH(cores) THEN
			RESULT = SAFEARRAY(0, LENGTH(cores) - 1)
			FOR res = 0 TO LENGTH(cores) - 1
				RESULT[res] = cores[res]
			NEXT
		ELSE
			RESULT = SPLIT(EMPTY)
		ENDIF
	FEND
ENDMODULE


やってみてもらえるとわかるんですが、TerminateするとUWSCが止められなくなります。
これ多分、UWSCUWSCでスレッドを管理していて、それが片付かないから終わらないんでしょうね。
ま、止めたいなら、Suspendくらいにしてください。