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
I wonder how the TThread.Synchronize method works:
e.g.
...
Synchronize(Foo);
Bar;
...
Does Foo _always_ finish _before_ Bar is executed?
Reagards,
J
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
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
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
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
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 :-) ?!?
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 :-) ?!?
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
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 TMultiReadExclusiveWriteSy nchronizer (TMREWSynchronizer for short) instad of synchronize
read all about it in help
there are situations where I use SendMessage for synchronization
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 TMultiReadExclusiveWriteSy
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.
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 .. :)
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 TMultiReadExclusiveWriteSy nchronizer is not an option for me.
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 TMultiReadExclusiveWriteSy
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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(eve nt_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
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(eve
// 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
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.
> 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.
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.