?
Solved

TThread.Synchronize()

Posted on 2003-03-04
13
Medium Priority
?
576 Views
Last Modified: 2007-12-19
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
0
Comment
Question by:j42
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 3
  • +2
13 Comments
 
LVL 1

Expert Comment

by:rfedyk
ID: 8063287
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.
0
 
LVL 2

Expert Comment

by:steve_hsk
ID: 8063384
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
0
 
LVL 2

Author Comment

by:j42
ID: 8063555
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
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 2

Expert Comment

by:steve_hsk
ID: 8063683
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 :-) ?!?
0
 
LVL 2

Author Comment

by:j42
ID: 8063773
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
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 8064167
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
0
 
LVL 6

Expert Comment

by:swift99
ID: 8069547
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.
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 8070245
wowy .. well I'm not into asm so .. :)
0
 
LVL 2

Author Comment

by:j42
ID: 8070628
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.
0
 
LVL 12

Accepted Solution

by:
Lee_Nover earned 400 total points
ID: 8070730
ofcourse TMREWSynch is an option .. the best one actually :)
to modify some data use
MREWS.BeginWrite;
try
  dostuff;
finally
  MREWS.EndWrite;
end;

to read some data use Begin/EndRead

about messages for synching ..
create a message handler in your form like
..
private
  procedure MyMessage(var AMsg: TMessage); message WM_MY_MSG;
..
WM_MY_MSG is your custom message above WM_USER (WM_USER + 1)

from the thread you simply call r:=SendMessage(FormsHandle, WM_MY_MSG, Param1, Param2);
(ofcourse you create the thread and set one of it's fields to your forms handle)

in the forms message handler do:
procedure Form1.MyMessage(var AMsg: TMessage);
begin
  case AMsg.WParam of
    0: AMsg.Result:=dostuff(LParam);
    1: AMsg.Result:=SomeOtherStuff(TMyThread(LParam));
  end;
end;

inside this message handler you can access the thread itself and also change it's properties
like in the second case where lparam is a pointer to your thread
from the thread : r:=SendMessage(FormsHandle, WM_MY_MSG, 1, Integer(Self));

I use this approach where I have multiple threads and TMREWSynch is not needed
but do read about TMREWSynch
0
 
LVL 2

Expert Comment

by:steve_hsk
ID: 8070995
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
0
 
LVL 2

Author Comment

by:j42
ID: 8071062
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.
0
 
LVL 6

Expert Comment

by:swift99
ID: 8071983
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.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Michael from AdRem Software outlines event notifications and Automatic Corrective Actions in network monitoring. Automatic Corrective Actions are scripts, which can automatically run upon discovery of a certain undesirable condition in your network.…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
Suggested Courses

765 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question