Link to home
Start Free TrialLog in
Avatar of j42
j42

asked on

TThread.Synchronize()

Hi experts,

I wonder how the TThread.Synchronize method works:
e.g.
  ...
  Synchronize(Foo);
  Bar;
  ...
Does Foo _always_ finish _before_ Bar is executed?

Reagards,
J
Avatar of rfedyk
rfedyk

It depends on what Foo is doing and what Bar is doing. However, I assume that your question relates to whether Bar is started before Foo finishes and the answer is yes. Synchronize (or Execute) launches Foo and then immediately starts Bar. The two processes are independent from that point on.
Hi J42...

The short answer is no, you cannot tell from this which would be execited first. The sychronise method : "Synchronize waits for the main VCL thread to enter the message loop and then executes the passed method." The reasoning is to avoid thread conflicts.

I can write more about conflicts if you wish.

If you wanted FOO to finish before BAR, then using a critical section would prevent your applicaiton from thread switching whilst in this C-Section ...

// Include the sycnchronise library
USES SyncObjs;

TYPE TMyThread = class (TThread);
PUBLIC
CONSTRUCTOR Create;  
DESTRUCTOR  Destroy;
PROCEDURE   Execute; Override;

PROCEDURE   FOO;
PROCEDURE   BAR;

... etc

// Declare the variable in your thread class
tcCriticalObj   : TCriticalSection;

... etc

END;

Implementation

... etc

// In the class constructor, create the C-Section
CONSTRUCTOR TMyThread.Create;
BEGIN
     // Inherited Default Thread Creation
     INHERITED Create;

     // Create the Critical Section Object
     tcCriticalObj := TCriticalSection.Create;
END;

PROCEDURE TMyThread.Destory;
BEGIN
     // Free the Critical Section
     tcCriticalObj.Free;

     // Inherited Default Thread Destruction
     INHERITED Destroy;
END;

PROCEDURE TMyThread.Execute;
BEGIN
     // Enter a critical thread section so NO other thread
     // can intervene and snatch CPU time ...
     tcCriticalObj.Enter;

     // Call FOO in the main Form
     Synchronise(FOO);

     // Leave the critical thread and allow other threads
     // to snatch CPU time
     tcCriticalObj.Leave;

     // Now FOO has finished call Bar;
     BAR;
END;

PROCEDURE TMyThread.FOO;
BEGIN
     // do stuff ...
END;

PROCEDURE TMyThread.BAR;
BEGIN
     // do stuff ...
END;

Hope this helps,
Steve
Avatar of j42

ASKER

Hi Steve,

first of all thank you very much. But maybe you have to rethink your understanding of critical sections (as I did a short time ago ;-). They do not prevent any thread from 'snatching CPU time'. They just suspend threads that try to access a criticals section if it is already in use by _another_ thread (and resume the thread later).

Delphi Help Critical Sections:
Critical sections only work if every thread uses them to access
the associated global memory. Threads that ignore the critical
section and access the global memory without calling Acquire (= Enter) can
introduce problems of simultaneous access.

Anyway thanks a lot



Hi rfedyk,

from Classes.pas:
procedure TThread.Synchronize(Method: TThreadMethod);
begin
  ...
  SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self));
  ...
end;

Delphi Help SendMessage():
... and does not return until the window
procedure has processed the message...

As I understand the above, the two processes are _not_ independent of each other. Can you help me with an example where Bar is started before Foo finishes (I already tried it myself - without success)? If neccessary I will increase points!



Regards
J
Hi J42,

you are right of course ... how about using events to signal to each thread the progress of FOO, to then start BAR ?

If you think this could work for you, I can put some code together.

Pseudo ...

Procedure thread_1.START
begin
     // call FOO
     Synchonise(FOO)

     // wait for signal
     Waitformultipleobjects(...)

     // reset the event if re-use req
     resetevent(...)
 
     // Start BAR
     BAR;
end;

procedure thread_1.BAR
begin
     // ....
end;

procedure thread_VCL.FOO
begin
     // start FOO tasks ...

     // signal thread 1 for BAR
     setEvent(...);

     // continue with FOO tasks ...
end;


maybe ... maybe not :-) ?!?
Avatar of j42

ASKER

Hi Steve,

thanks again. WaitForMultipleObjects() will do fine! But my question is not how to make sure Foo is finished but if it is neccessary to check it. I guess it is not but I am not sure. Since my task is very time critical (image processing) I am glad about every instruction I can avoid...



Hi all,

The clue to the problem is the
  SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self));
call in the Synchronize method. When will it return? As soon as the message is read by the VCL thread? Will it wait until FMethodWhatever is done?



Regards
J
it'll wait until the message returns
that means when the window proc of ThreadWindow exits
>> Will it wait until FMethodWhatever is done? << YES
there is no overlaping of execution here as rfedyk wrote
so ..

Synchronize(foo);
Bar;

first foo is executed in the main thread and after it's done Bar is executed in the calling thread

for performance reasons I use TMultiReadExclusiveWriteSynchronizer (TMREWSynchronizer for short) instad of synchronize
read all about it in help

there are situations where I use SendMessage for synchronization
Synchronize works by building a Windows message, and then firing the main thread with the message that will cause the specified method to be fired.  Synchronize waits for completion of the main thread before returning, as Lee said.  It is limited to around 300,000 calls per second on an 800 MHz system.

The TMREWSynchronizer is faster, but is still far from speedy, limited to about 500,000 calls per second on an 800 MHz system.

Writing a fast synchronization mechanism is non-trivial, and will involve some assembly work.  It is dependent upon the use of the LOCK prefix and the BTS and BTR instructions.  Depending on the degree of locking safety and flexibility required, speeds of 2,500,000 to 8,500,000 calls per second are possible that are thread and multi-processor safe.
wowy .. well I'm not into asm so .. :)
Avatar of j42

ASKER

swift99,
I really appreciate these data!

Lee,
can I get a short hint how to use SendMessage for synchronizing? As I use VCL calls I guess TMultiReadExclusiveWriteSynchronizer is not an option for me.
ASKER CERTIFIED SOLUTION
Avatar of Lee_Nover
Lee_Nover

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi guys ... there's some nice info here ...

Maybe I mis-understand again ;-) , but to sync two threads isn't it a case of designing the logic around what needs to be sync'd, as oppossed to choosing a VCL method ?

(a bad) example ...

global def ... g_iParam : Integer;

thread 1 ...
FOO part A ... g_iParam = 5;
sync necessary : WaitForMulitpleObjects(event_A or Msg_A)
// after sync, g_iParam is ready (sync'd)
FOO part B ... (with g_iParam = 10;)
END

thread 2 ...
BAR part A ... g_iParam = 10;
sync with thread 1 : SetEvent(event_a) or SendMessage(Msg_A)
// optional : force thread switch : sleep(0);
BAR part B ...
END

Interesting topic ... that's probably all the use(?) I can be :-)

Hope you get the problem solved somehow,
Steve
Avatar of j42

ASKER

Thank you all for supplying help!

> ofcourse TMREWSynch is an option .. the best one actually :)
> to modify some data use
> MREWS.BeginWrite;
> try
>  dostuff;
> finally
>  MREWS.EndWrite;
> end;
In my app dostuff will access forms etc. so I have to transfer it to the main thread.
You're right steve - multi-threaded programming is much more intensive than choosing a VCL method (Synchronize) or using a Windows signalling object (TMREWSynchronizer).

The problem with giving more advice than j42 asked for is that he dodin't give us much detail about the problem or the system(s) he is running on.  There is a world of a difference between an asynchronous download with a progress bar, a multithreaded transaction based server application, and a full blown PVM based engineering model for a beowulf system.  The threading techniques you use will differ immensely for each problem.

In the VCL and Windows API, Borland and M$oft engineers have already done the hard work for you for most desktop applications, so in that environment it is most effective to reuse their work.  

In his last post, where more details are given, it is apparent that most of his work should be done by passing messages to the main thread, without any need for synchronization.  However, that requires another level of abstraction that he may not be ready for.  The next best alternative is to use the Synchronize method, which is asiest for newer programmers to understand.