mauro russo wrote:
> what happens when a TThread T object, stopped on
> a Synchronize call (having as parameter a TMethod M),
> is terminated by the API TerminateThread, executed
> in the main thread?

Very bad things. Have you read the documentation for that function? Heed 
_all_ the advice you've ever read about TerminateThread: Don't call it.

> a) Is the method M executed also if T is already terminated?

T does not terminate. T is just a plain old Delphi object. T was in 
possession of an OS thread resource, and that thread suddenly popped out 
of existence, so T's Handle property is invalid, but there's nothing in 
T that knows that.

> b) what if the TerminateThread is executed in a different thread, but not the 
> main thread?
>     Is M executed only if it was already started?

TerminateThread doesn't care what thread it's called from. It's just as 
destructive no matter what.

The exact consequences depend on what your program was doing at the time 
you called TerminateThread. TThread.Synchronize works in two different 
ways depending on your Delphi version.

In older versions, Synchronize calls SendMessage to send a message to a 
window owned by the main thread. When the main thread calls a 
message-checking function (including GetMessage, PeekMessage, and 
SendMessage), the waiting message from Synchronize will be handled. That 
entails calling the method pointer included in the message's parameters.

The thread that called SendMessage is blocked waiting for the receive to 
grab the message off the queue and finish calling the handler for that 
message. If the sender thread disappears, I imagine the message remains 
in the message queue, so the main thread will still get notification 
that th message is there, and will still handle it. There will just be 
no thread left blocking waiting for a response.

In newer Delphi versions, Synchronize puts method pointers into a queue 
of their own. It does not use the message queue. It associates an event 
with the method, notifies the main thread that the queue is non-empty, 
and then blocks on the event.

Once again, if the waiting thread disappears, the main thread won't know 
it. It will still grab the method off the queue and execute it. It will 
still signal the event when it's complete. But no one will be left 
waiting on that event.

In either case, the main thread may encounter an error when it tries to 
determine what method to call. TThread.Synchronize has a TSyncProc 
record that it fills with the method pointer and other information for 
the main thread. It allocates that record as a local variable, which 
means it's on the stack, and then uses a pointer to that variable when 
it calls SendMessage or puts the pointer on the method queue. Since 
TerminateThread releases the stack memory associated with the OS thread, 
the main thread is stuck with an invalid pointer when it finally notices 
that there's a synchronized method to call.

You will still have an object reference for the TThread object. It 
doesn't become nil when the OS thread is destroyed. The TThread object 
does not call its OnTerminate event handler, and its Terminated property 
is not set to True. Trying to free that object will cause it to try to 
terminate the SO thread gracefully, but of course that won't work 
because there's no thread there to receive the commands TThread's 
destructor tries to call.

-- 
Rob

Reply via email to