-
I think there is a bug in TThread implementation in KOL (ver 2.88) Try to use WaitFor when in thread Execute there is at least one Synchronize method. It will stuck. btw. Terminate method is using dangerous TerminateThread winAPI (memory leak is probable)
Please check it maybe it is fixed already, maybe my solution is not good, just look at it.
I remember that I fixed (or made workaround) that by allowing to set Terminated from outside of thread and using
if not FTerminated then begin Terminate; WaitFor; end;
inside TThread.Destroy then a check in Synchronize removed infinite loop.
I'm sorry I can't provide a diff.
Look at code below and compare to official:
//[destructor TThread.Destroy] {$IFDEF ASM_VERSION} {$ELSE ASM_VERSION} //Pascal destructor TThread.Destroy; begin RefInc; if not FTerminated then begin Terminate; WaitFor; end; if (FHandle <> 0) then CloseHandle(FHandle); {$IFDEF PSEUDO_THREADS} if StackBottom <> nil then FreeMem( StackBottom ); if MainThread = @ Self then begin TimeEndPeriod( 10 ); AllThreads.Free; end else if MainThread <> nil then begin MainThread.AllThreads.Remove( @ Self ); if MainThread.AllThreads.Count <= 1 then Free_And_Nil( MainThread ); end; {$ENDIF} inherited; end; {$ENDIF ASM_VERSION}
//* //[procedure TThread.Synchronize] procedure TThread.Synchronize(Method: TThreadMethod); begin {$IFDEF PSEUDO_THREADS} Method; {$ELSE} if Terminated then Exit; FMethod := Method; if Applet <> nil then SendMessage( Applet.fHandle, CM_EXECPROC, 0, Integer( @Self ) ); {$ENDIF} end;
//[procedure TThread.SynchronizeEx] procedure TThread.SynchronizeEx( Method: TThreadMethodEx; Param: Pointer ); begin Assert( Param <> nil, 'Parameter must not be NIL' ); {$IFDEF PSEUDO_THREADS} Method( TMethod( Method ).Data, Param ); {$ELSE} if Terminated then Exit; FMethodEx := Method; SendMessage( Applet.fHandle, CM_EXECPROC, Integer( Param ), Integer( @Self ) ); {$ENDIF} end;
//* //[procedure TThread.Terminate] procedure TThread.Terminate; begin {$IFDEF PSEUDO_THREADS} if Assigned( MainThread ) then if MainThread.CurrentThread = @ Self then MainThread.NextThread; {$ELSE} Suspend; FTerminated := true; if Suspended then Resume; Waitfor; //TerminateThread(FHandle,0); //FTerminated := True; {$ENDIF} end;
//* //[function TThread.WaitFor] function TThread.WaitFor: Integer; begin RefInc; Result := -1; {$IFDEF PSEUDO_THREADS} while not Terminated do Resume; if Terminated then Result := FResult; {$ELSE} if FHandle = 0 then Exit; WaitForSingleObject(FHandle, INFINITE); GetExitCodeThread(FHandle, DWORD(Result)); {$ENDIF} RefDec; end;
function TThread.WaitForTime(T: DWORD): Integer; {$IFDEF PSEUDO_THREADS} var LimitTime: DWORD; {$ENDIF} begin {$IFDEF PSEUDO_THREADS} LimitTime := GetTickCount + T; RefInc; while not Terminated and (GetTickCount < LimitTime) do Resume; Result := -1; if Terminated then Result := FResult; RefDec; {$ELSE} Result := WAIT_OBJECT_0; RefInc; if FHandle = 0 then Exit; Result := WaitForSingleObject(FHandle, T); if Result = WAIT_OBJECT_0 then GetExitCodeThread(FHandle, T); RefDec; {$ENDIF} end;
|