[Lazarus] TThread.WaitFor blocks the main event loop under Linux

Michael Van Canneyt michael at freepascal.org
Tue Oct 12 13:06:09 CEST 2010



On Tue, 12 Oct 2010, Graeme Geldenhuys wrote:

> Op 2010-10-12 11:43, Michael Van Canneyt het geskryf:
>>
>> I am all for it, but first explain the following:
>>
>> WaitFor by itself cannot cause deadlock.
>>
>> There must be another call as well, I assume Synchronize(), in the thread
>> that you are waiting on. Is that correct  ?
>
> Correct.
>
>
>> Because, if it is so, then you are simply programming wrong. Your coding
>> style causes deadlock.
>>
>> Thread 1 (main thread) says: I'll wait for thread 2;
>> Thread 2 says: I'll wait for thread 1 (implicitly, in sycnhronize)
>
> Please take a look at tiOPF's tiLog and tiThread units to see the usage.
> Taking the logging units as an example. So loggers need synchronize (eg;
> when writing to a GUI log window), other loggers don't need synchronize
> (eg; when outputing to the console).
>
> Threading 101: If you access the GUI from a thread, you need to use
> synchronize.

[snip]

> threads, logger threads, thread list, app server thread etc... Simply
> search the tiOPF source for 'WaitFor' and you'll find lots of different
> examples. I can't think all of them is just wrong??

Of course. It _IS_ wrong programming. Under windows you get away with it,
because the messaging system bypasses the threads.

But strictly speaking in thread API terms, you have a classical deadlock 
situation. Nowhere does it say that synchronize() will work if the main
thread waits for a particular thread.

>From the Delphi docs:

"Synchronize causes the call specified by Method to be executed using the
main thread, thereby avoiding multi-thread conflicts. If you are unsure
whether a method call is thread-safe, call it from within the Synchronize
method to ensure that it executes in the main thread.

Execution of the thread current is suspended while Method executes in the
main thread."

Note that it doesn't say WHEN it will be executed. Just that, if executed,
it is in the main thread.

and in "WaitFor" it says:

"Call WaitFor to obtain the value of ReturnValue when the
thread finishes executing. WaitFor doesn't return until the thread
terminates, so the thread must exit either by finishing the Execute method
or by exiting when the Terminated property is true."

There you have it. Nowhere does it say that if the main thread is blocked,
your synchronize() method will be executed nonetheless. Indeed, both specs
explicitly say that the calling thread is suspended or blocked (!) till the 
call returns.

So strictly speaking, your (or tiOPF's) code is assuming something which is
in no way guaranteed by the API, and thus create deadlock.

>> So what you propose is a change in specs, namely: WaitFor() is blocking
>> *except* in the main thread, where synchronize calls are still executed.
>> Main reason for this change is to avoid potential deadlocks.
>>
>> Is this correct ?
>
> Yes, that sounds about right.

So you agree this is a change in specs ?

We can argue that this change is necessary (there is a strong point for it).

But as documented, I think I demonstrated that the FPC RTL works correct, 
and the programs are simply wrong.

I will see about changing the specs.

Michael.




More information about the Lazarus mailing list