I have only limted experience with threads. I want to read some fundamental database tables in parallel and I need to wait until all tables are read before the program can reasonably progress. In that regard, blocking the main thread is OK for me.
This code (simplified) works fine:
procedure ReadDBMultiThread;
var ATasks : Array of ITask;
begin
SetLength(ATasks, 3);
ATasks[0] := TTaskCreate(procedure() begin DB_ReadTable1; end);
ATasks[1] := TTaskCreate(procedure() begin DB_ReadTable2; end);
ATasks[2] := TTaskCreate(procedure() begin DB_ReadTable3; end);
ATasks[0].Start;
ATasks[1].Start;
ATasks[2].Start;
TTask.WaitForAll(ATasks);
end;
However, let's say I would like to update the main form to show the progress, i.e. which database table has already been read (or do any other necessary main thread work). Obviously, I cannot use Synchronise() because that would lead to a dead lock with WaitForall() and I cannot use Queue() because that would by executed after WaitForAll() finishes.
So, is there a good solution to solve this "WaitForAll vs Synchronise" situation? I guess, this must be a situation many people come into... the need to wait for all being finished, but wanting to update the main thread...
I thought about something like this, given in pseudo-code, replacing the WaitForAll() statement:
repeat
Applicaton.ProcessMessages; // or "ProcessSynchroniseMessages"
until "AllTaskCompleted"(ATasks);
Would this work? Is there a better solution?
Could I write a own routine like ProcessMessages, but restricted to Synchronise messages, i.e. other main form events not being executed until later?
Many thanks in advance!
TThread.Synchronize()
and TThread.Queue()
do not use window messages (well, there is a message to "wake up" the main thread to signal a pending request, but the actual synchronizing itself is not message-based). Requests are put into a global queue, which the main thread checks when it is sitting idle, or when it detects the "wake up" message. You can pump that same queue manually by calling the Classes.CheckSynchronize()
function directly:
while not TTask.WaitForAll(ATasks, 1000) do
begin
// process any pending TThread.Synchronize() and TThread.Queue() requests
CheckSynchronize(0);
// process any pending UI paint requests, but not other messages
Application.MainForm.Update;
// anything else you need...
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With