Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2014-09

PostMessage return value

51 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Xiangrong Fang

Hi All,

I try to use PostMessage for inter-thread communication.

After reading the wiki and source code, I found that:

1) PostMessage is defined in winapih.inc, altough I confirmed using a simple test program that it also work under linux.

2) In the document it is not mentioned when PostMessage will return false? In practice, is it necessary to check return value of PostMessage?

Thanks!
Shannon
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140914/5cd9332e/attachment.html>

Reply by email

Michael Schnell
to Xiangrong Fang
Xiangrong Fang wrote 6 lines
1) PostMessage is defined in winapih.inc, altough I confirmed using a simple test program that it also work under linux.

Yep.

But it's old-style Windowish stuff.

For better clearness, flexibility and portability I would use Application.QueueAsyncCall instead (Or TThread.Queue, if you are on the svn Version of fpc and would like to do it Delphi-compatible).

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140915/95968a22/attachment.html>

Reply by email

Xiangrong Fang
to Michael Schnell

2014-09-15 17:12 GMT+08:00 Michael Schnell :

Show quoted text 5 lines
For better clearness, flexibility and portability I would use Application.QueueAsyncCall instead (Or TThread.Queue, if you are on the svn Version of fpc and would like to do it Delphi-compatible).

?I would like to use the most clear, simple FPC way of inter-thread? c
?ommunication / locking of shared resources. I DO need cross platform (linux/windows), but I do NOT want Delphi compatibility, my app only compiles with FPC/Lazarus :-)

Finally, I prefer to use the latest GENERALLY-AVAIABLE version of FPC, which is 2.6.4 now, to save me trouble to setup development version of FPC on any PC I would need to run FPC :-)

Any more hint please? Thanks a lot!

Xiangrong?
?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140915/f7ecc4b8/attachment.html>

Reply by email

Xiangrong Fang
to Michael Schnell

2014-09-15 17:23 GMT+08:00 Michael Schnell :

In that case I definitely would use Application.QueuAsyncCall.

If I understand correct, from this page:

http://wiki.freepascal.org/Asynchronous_Calls

QueueAsyncCall is, like what its name suggest, doing this in asynchronous favor -- it execute queued method in the next message loop (while Application.ProcessMessages takes place, right?).

But what I need PostMessage for is to notify main thread (or another thread) that a worker thread finished its job, so that the thread manager can start a new thread to do the remaining work.

Anyway, is PostMessage considered "deprecated" or "shall be used on windows only"? Is there a better way to do what I want?

Thanks,
Xiangrong
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140915/305d1bbd/attachment.html>

Reply by email

Sven Barth
to Xiangrong Fang
"Xiangrong Fang" wrote 12 lines
2014-09-15 17:23 GMT+08:00 Michael Schnell : > > > In that case I definitely would use Application.QueuAsyncCall. If I understand correct, from this page: http://wiki.freepascal.org/Asynchronous_Calls QueueAsyncCall is, like what its name suggest, doing this in asynchronous

favor -- it execute queued method in the next message loop (while Application.ProcessMessages takes place, right?).

But what I need PostMessage for is to notify main thread (or another

thread) that a worker thread finished its job, so that the thread manager can start a new thread to do the remaining work.

PostMessage is asynchronous as well. For a synchronous way I'd suggest you to take a and corresponding documentation and
tutorials.

Note: Synchronize can only notify the main thread. Note2: The synchronous alternative to PostMessage would be SendMessage, though I don't know whether Lazarus provides this in a cross platform way

If you want to use a separate thread ("dispatcher") for enqueueing new work you should create an event that you pass to this thread and the worker threads. The dispatcher waits on the event and the worker threads will signal the event once they are done. Of course you'll likely also signal the event when new work items are queued that need to be dispatched.

Regards,
Sven
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140915/21ddb978/attachment.html>

Reply by email

Michael Schnell
to Xiangrong Fang: 2014-09-15 17:23 GMT+08:00 Michael Schnell : If I understand correct, from this page:…
Xiangrong Fang wrote 14 lines
2014-09-15 17:23 GMT+08:00 Michael Schnell < <mailto:>>: In that case I definitely would use Application.QueuAsyncCall. If I understand correct, from this page: http://wiki.freepascal.org/Asynchronous_Calls QueueAsyncCall is, like what its name suggest, doing this in asynchronous favor -- it execute queued method in the next message loop (while Application.ProcessMessages takes place, right?).

That is exactly what Postmessage does (in combination with procedure ... message).

In fact you don't need to call Application.ProcessMessages (on that behalf). In fact (usually) the main thread is not supposed to do long lasting or even polling loops to be made of run-to-completion events. QueueAsyncCall just schedules another run-to-completion event for you and same will automatically happen as soon as the main thread is free (having done all previously scheduled events).

But what I need PostMessage for is to notify main thread (or another thread) that a worker thread finished its job, so that the thread manager can start a new thread to do the remaining work.

Neither QueueAsyncCall nor Postmessage have anything to do with finishing a thread (unless you call it right before the end of the thread's execute procedure).

Anyway, is PostMessage considered "deprecated" or "shall be used on windows only"?

Not really depreciated but IMHO (when used for thread to main thread signaling) it's a relict from Delphi's widows-only heritage.

Is there a better way to do what I want?
As said: you can do Application.QueueAsyncCall() right before the end of
the thread's execute procedure;

(Or you can simply start the new worker thread there instead of having the main thread do this if this might be appropriate.)

-Michael

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140915/8c673c45/attachment-0001.html>

Reply by email

Michael Schnell
to Xiangrong Fang: 2014-09-15 17:23 GMT+08:00 Michael Schnell : If I understand correct, from this page:…
Xiangrong Fang wrote
But what I need PostMessage for is to notify main thread (or another thread)

You can only notify the main thread. There is no (standard) means to notify another thread, as they don't have an event queue.

OTOH a worker thread is allowed to wait a long time for an event (e. g via TCriticalSection), while doing this in the main thread would freeze the GUI.

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140915/d4a7e469/attachment.html>

Reply by email

Xiangrong Fang
to Sven Barth: favor -- it execute queued method in the next message loop (while…

2014-09-15 20:34 GMT+08:00 Sven Barth :

Show quoted text 6 lines
If you want to use a separate thread ("dispatcher") for enqueueing new work you should create an event that you pass to this thread and the worker threads. The dispatcher waits on the event and the worker threads will signal the event once they are done. Of course you'll likely also signal the event when new work items are queued that need to be dispatched.

In Michael's previous email, I understand that using PostMessage and QueueAsyncCall will does the same thing.

How do I use Event to achieve the same? It seems that I can have N threads "listen" to the same event, but cannot have the main thread to "listen" to N different events?

Anyway, if I use Event I'll do some more reading of the document. For now, I would like to know, performance-wise, which way is better? Using QueueAsyncCall/PostMessage or RTLEvent*?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140915/9b22898e/attachment.html>

Reply by email

Michael Schnell
to Xiangrong Fang
Xiangrong Fang wrote
How do I use Event to achieve the same?

What do you mean by "Event" ?

It seems that I can have N threads "listen" to the same event, but cannot have the main thread to "listen" to N different events?

In fact Windows does provide event (aka "Message") queues for all threads out of the boy, Linux does not provide any event queues.

Lazarus (like Delphi) provides some support for an Event Queue for the Main thread. Lazarus does this both in Windows and Linux (and Mac OS). The queue can be fed by GUI events, (non-Delphi)
Application.QueueAsyncCall (and TThread.Synchronize and - with the FPC svn version - TThread.Queue).

There is no support by the language for Event Queues for worker Threads. In Windows you could use messages directly by API calls, in Linux you could use Pipes with the appropriate API calls like "open", "select", "epoll", ...

For now, I would like to know, performance-wise, which way is better? Using QueueAsyncCall/PostMessage or RTLEvent*?

Performance wise it's better not to destroy and create your threads but to manage a thread pool and assign work to the threads as appropriate.

Here you would have the threads wait for work e.g. by trapping themselves in a TCriticalSection for each one.

Now the Main thread can easily free a thread after it assigned work to it (e.g. by providing a callback function that is to be called in TThread.Execute). If work is done, the Thread could notify the manager (in the main thread) by Application.QueueAsyncCall or TThread.Queue. TThread. Synchronize would not harm in this case either, as the thread at that time has nothing to do anyway.

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140915/8fd80b56/attachment.html>

Reply by email

Xiangrong Fang
to Michael Schnell

2014-09-15 21:44 GMT+08:00 Michael Schnell :

Show quoted text 14 lines
Performance wise it's better not to destroy and create your threads but to manage a thread pool and assign work to the threads as appropriate. Here you would have the threads wait for work e.g. by trapping themselves in a TCriticalSection for each one. Now the Main thread can easily free a thread after it assigned work to it (e.g. by providing a callback function that is to be called in TThread.Execute). If work is done, the Thread could notify the manager (in the main thread) by Application.QueueAsyncCall or TThread.Queue. TThread. Synchronize would not harm in this case either, as the thread at that time has nothing to do anyway.

That's exactly what I planed to do. But I don't know "CriticalSections" can be used in here. My original thinking is that, by the end of Execute, I call either PostMessage or QueueAsyncCall to notify main thread that the current thread finished its work. The main thread, in its message handler then know from a status variable that this thread is in suspended status, then assign a new work to it and call its Execute() method again.

Is that ok? To be exact, when a thread's execute() finished, it will go to a "sleep" status, and can be reused by calling execute() again, right?

Even this works, if it is performance-wise not optimal, please give me a short example of how to use CriticalSection for this purpose.

Thanks a lot.

Xiangrong
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140915/8f2e37ed/attachment-0001.html>

Reply by email

Michael Schnell
to Xiangrong Fang
Xiangrong Fang wrote 22 lines
2014-09-15 21:44 GMT+08:00 Michael Schnell < <mailto:>>: Performance wise it's better not to destroy and create your threads but to manage a thread pool and assign work to the threads as appropriate. Here you would have the threads wait for work e.g. by trapping themselves in a TCriticalSection for each one. Now the Main thread can easily free a thread after it assigned work to it (e.g. by providing a callback function that is to be called in TThread.Execute). If work is done, the Thread could notify the manager (in the main thread) by Application.QueueAsyncCall or TThread.Queue. TThread. Synchronize would not harm in this case either, as the thread at that time has nothing to do anyway. That's exactly what I planed to do. But I don't know "CriticalSections" can be used in here.

Why not (of course there might be alternatives).

My original thinking is that, by the end of Execute, I call either PostMessage or QueueAsyncCall to notify main thread that the current thread finished its work.

OK. Moreover TThread.Queue and TThread.Synchronize will work.

The main thread, in its message handler

(This is the procedure given in Application.QueueAsyncCall, TThread.Queue and TThread.Synchronize)

then know from a status variable that this thread is in suspended status,

OK, suspend will work similar to TCrtiticalSection. But for me Suspend is a bit suspicious, as there is no direct Linux and Information-Science equivalent to same (while TCriticalSection directly maps to a Semaphore).

then assign a new work to it and call its Execute() method again.

I don't know how to " call its Execute()". I feel that you can't leave the Execute procedures without killing the thread. So you need to call the work-procedure from the execute procedure.

Is that ok? To be exact, when a thread's execute() finished, it will go to a "sleep" status,

No. It will die.

and can be reused by calling execute() again, right?

AFAIK: No.

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140915/12fd7566/attachment.html>

Reply by email

Mattias Gaertner
to Xiangrong Fang: 2014-09-15 21:44 GMT+08:00 Michael Schnell : That's exactly what I planed to do. But I…
Show quoted text 7 lines
[...] That's exactly what I planed to do. But I don't know "CriticalSections" can be used in here. My original thinking is that, by the end of Execute, I call either PostMessage or QueueAsyncCall to notify main thread that the current thread finished its work. The main thread, in its message handler then know from a status variable that this thread is in suspended status, then assign a new work to it and call its Execute() method again.

Then write your thread Execute as a loop, calling Synchronize. Synchronize pauses the thread, waiting for the main thread, calling the method in the main thread, when method ended continuing thread.

See
http://wiki.freepascal.org/Multithreaded_Application_Tutorial

Mattias

Reply by email

Xiangrong Fang
to Michael Schnell: Why not (of course there might be alternatives). OK. Moreover TThread.Queue and…

2014-09-15 22:30 GMT+08:00 Michael Schnell :

Show quoted text 9 lines
Is that ok? To be exact, when a thread's execute() finished, it will go to a "sleep" status, No. It will die. and can be reused by calling execute() again, right? AFAIK: No.

What's the meaning of "die"? By "calling execute()" I simply mean call its Start() method. I will create the thread in "Suspended" mode, i.e. Create(True). So I hope I can Start() it again after Execute() ended.

That's what I understand where the document said Resume() is deprecated and replaced by Start(), which means, Start() can be called multiple times?? -------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140916/522d74ba/attachment.html>

Reply by email

Sven Barth
to Xiangrong Fang
Xiangrong Fang wrote 16 lines
2014-09-15 22:30 GMT+08:00 Michael Schnell < <mailto:>>: > Is that ok? To be exact, when a thread's execute() finished, it > will go to a "sleep" status, No. It will die. > and can be reused by calling execute() again, right? AFAIK: No. What's the meaning of "die"? By "calling execute()" I simply mean call its Start() method. I will create the thread in "Suspended" mode, i.e. Create(True). So I hope I can Start() it again after Execute() ended. That's what I understand where the document said Resume() is deprecated and replaced by Start(), which means, Start() can be called multiple times??

No. A thread's Execute() method is only called once. If it exits the thread ends to never return.
Suspend() uses operating system functionality to stop a thread's execution whereever it currently is (dangerous!) and Resume() let's the thread continue its execution from that point on. Now with the deprecation of these two methods a new method was needed to get the thread out of the "create suspended" state. Thus Start() was born (internally Start() is basically just an alias for Resume()). It's only reason of existance is to start a thread that was created as suspended.

Regards,
Sven

Reply by email

Xiangrong Fang
to Michael Schnell

Hi Michael,

Could you please post it somewhere, e.g. github?

Thanks!

2014-09-16 19:44 GMT+08:00 Michael Schnell :

Show quoted text 16 lines
I did a draft of a TThreadPool class. Most of it works (creating assigning and re-assigning tasks works, stopping the thing still produces an exception). If anybody wants to test it I can post the project. -Michael -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140916/2ca75d42/attachment.html>

Reply by email

Michael Schnell
to Xiangrong Fang
Xiangrong Fang wrote
But where is the source please?

(I don't post attachments unless explicitly requested)

Here you are.

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140917/a7f114b6/attachment.html> -------------- next part --------------
A non-text attachment was scrubbed...
Name: tthreadpool.zip
Type: application/x-zip-compressed
Size: 4537 bytes
Desc: not available
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140917/a7f114b6/attachment.bin>

Reply by email

Xiangrong Fang
to Michael Schnell

2014-09-17 16:09 GMT+08:00 Michael Schnell :

Here you are.

It is strange that it works on one computer but does not work (or partially work) on another -- causing SIGSEGV. Both running same environment - Ubuntu 14.04 x86_64 fpc 2.6.4 laz1.2.4.

I don't understand how the critical section works. I try to write a test program, which does the following:

The main thread create a predefined number of threads, which start running on creation. The thread's wait for a critical section variable, when acquired, try to crack a given integer, see if it is prime number or not, report back to main thread about the result and get the next number to crack from main thread. The main thread output crack result of every thread in a memo box.

I simply don't know how to coordinate the threads. And got many strange errors like

Semaphore init failed (maybe too many running threads)? SIGABT
SIGTRAP

something wrong in raise.c, laz asked me if I want to locate myself, blahblah.

May I send you my source, or you can write a demo for me? Thanks a lot!

Xiangrong
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140917/6db890f7/attachment.html>

Reply by email

Graeme Geldenhuys
to Michael Schnell: I did a draft of a TThreadPool class. Most of it works (creating assigning and…
Michael Schnell wrote
I did a draft of a TThreadPool class. Most of it works (creating assigning and re-assigning tasks works, stopping the thing still produces an exception).

I haven't followed this whole thread, but I can add that the tiOPF project (on SourceForge) has had a threadpool class for many years. Well unit tested too.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Michael Schnell
to Xiangrong Fang: 2014-09-17 16:09 GMT+08:00 Michael Schnell : It is strange that it works on one computer…
Xiangrong Fang wrote 10 lines
2014-09-17 16:09 GMT+08:00 Michael Schnell < <mailto:>>: Here you are. It is strange that it works on one computer but does not work (or partially work) on another -- causing SIGSEGV. Both running same environment - Ubuntu 14.04 x86_64 fpc 2.6.4 laz1.2.4.

That in fact is strange.
Of course here (Linux x86_32, newest svn version of fpc and Lazarus) it does work, otherwise I would not have posted it.

Did you try the unmodified project ?

I don't understand how the critical section works.

TCriticalSection is a straight forward semaphore. (-> https://en.wikipedia.org/wiki/Semaphore_%28programming%29 )

Of course there are several kinds of semaphores out there:
- binary and counting: TCriticalSection is binary
- blocking or not blocking when a Thread/Task tries to take it while it already holds it: TCriticalSection does not block
- allowing or disallowing a Thread/Task to free it even though it is helt by another Thread/Task: TCriticalSection disallows this.

Show quoted text 8 lines
I try to write a test program, which does the following: The main thread create a predefined number of threads, which start running on creation. The thread's wait for a critical section variable, when acquired, try to crack a given integer, see if it is prime number or not, report back to main thread about the result and get the next number to crack from main thread. The main thread output crack result of every thread in a memo box.

Are you sure that only the main thread does anything related to the GUI ? This is strictly forbidden for worker threads and results in SIGSEGV. This is why TThreadPool offers events OnReady events that are run in the main thread. ("synchronized").

Show quoted text 5 lines
I simply don't know how to coordinate the threads. And got many strange errors like Semaphore init failed (maybe too many running threads)?

I never saw such an error. Anyway, I suppose you will do multithreading just for sake of performance. Here running more threads than CPUs/Hardware Threads does not make sense, as it will slow down the calculation due to unnecessary time slice related task switches which result in local cache misses (Linux tries to keep a thread on the same CPU if possible, but this is only possible when there are not much more active threads than CPUs). So there will never be "too many" threads.

In any case start with simple stuff (e.g. using my example and replacing the "Tasks" with first simple and then more complex "Execute" procedures.

something wrong in raise.c, laz asked me if I want to locate myself, blahblah.

I have no idea what "raise.c" is supposed to be.

Show quoted text 5 lines
May I send you my source, or you can write a demo for me? Thanks a lot!

I already did provide you with a demo. I can enhance this for you if you have a certain request.

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140918/1640ebdd/attachment.html>

Reply by email

Michael Schnell
to Graeme Geldenhuys: I haven't followed this whole thread, but I can add that the tiOPF project (on…
Graeme Geldenhuys wrote
I haven't followed this whole thread, but I can add that the tiOPF project (on SourceForge) has had a threadpool class for many years. Well unit tested too.

Great ! Thanks. I'll take a look.

I did the TThreadPool class just for fun. I'll compare the two thingies and come back with some comments.

Maybe finally it might be nice to add something like this to the fpc rtl (I on purpose did in in a way that does not require LCL, but allows for using it) or create a Lazarus package from it to be provided in a fpc/Lazarus related location.

-Michael

Reply by email

Xiangrong Fang
to Michael Schnell

2014-09-18 16:13 GMT+08:00 Michael Schnell :

Show quoted text 5 lines
I did the TThreadPool class just for fun. I'll compare the two thingies and come back with some comments.

?I don't quite understand the logic or difference between critical section ?

?and events. My feeling is that to do synchronization you will have to use event (I will do some test to verify that). Because when you use critical section, like in your ThreadPool:

procedure TThreadPoolThread.Execute;
begin
  while not Terminated do begin
    Wait.Aquire;
    ...
  end;
end;

You are actively try to aquire the CS. i.e. After you finish this loop and notify the main thread, how do you ensure which thread will get this CS next? The main thread or this worker thread?

?But if you use something like this (I don't know if the syntax or usage is correct, just show my thinking):

procedure TThreadPoolThread.Execute;
begin
  while not Terminated do begin
    RTLEventWaitFor(Wait);
    ...
  end;
end;
?
?Then, you are PASSIVELY wait for the event which will be set/reset from
OUTSIDE this working thread.

That's what confused me how can you use a CS for the purpose of thread synchronization!

Yesterday I read your ThreadPool source code, and cannot understand how you control which thread can get the "Wait" CS, rather than just let the 2 thread compete for it. Could you please explain the logic behind this?

Thanks!

Xiangrong?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140918/90b5486a/attachment.html>

Reply by email

Michael Schnell
to Xiangrong Fang

You said that you in fact did need or do an OnReady Event for each thread.

I just added that feature to TThreadPool: now each user Task (TTask class) can be provided an "OnReady" Notify function.

Let me know if you want the extended code.

-Michael

Reply by email

Michael Schnell
to Xiangrong Fang: 2014-09-18 16:13 GMT+08:00 Michael Schnell : ?I don't quite understand the logic or…
Xiangrong Fang wrote 5 lines
I don't quite understand the logic or difference between critical section and events.

They have nothing in common.

TCriticalSection is a Semaphore (see Wikipedia)

An event is a callback procedure ->
https://en.wikipedia.org/wiki/Callback_%28computer_programming%29

Sorry, but you will not be able to do such a project unless you understand such basic computer science primitives.

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140918/fb445016/attachment.html>

Reply by email

Michael Schnell
to Xiangrong Fang: 2014-09-18 16:13 GMT+08:00 Michael Schnell : ?I don't quite understand the logic or…
Xiangrong Fang wrote
how can you use a CS for the purpose of thread synchronization!

Thread synchronization is the only cause why TCriticalSection has been invented (and provided with Delphi decades ago by Borland).

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140918/a8441cb5/attachment.html>

Reply by email

Michael Schnell
to Xiangrong Fang: 2014-09-18 16:13 GMT+08:00 Michael Schnell : ?I don't quite understand the logic or…
Xiangrong Fang wrote 11 lines
2014-09-18 16:13 GMT+08:00 Michael Schnell < <mailto:>>: I did the TThreadPool class just for fun. I'll compare the two thingies and come back with some comments. I don't quite understand the logic or difference between critical section and events.

In what extent is this an answer to the phrase cited ?

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140918/8b83e8cf/attachment.html>

Reply by email

Michael Schnell
to Xiangrong Fang: 2014-09-18 16:13 GMT+08:00 Michael Schnell : ?I don't quite understand the logic or…
Xiangrong Fang wrote 7 lines
Yesterday I read your ThreadPool source code, and cannot understand how you control which thread can get the "Wait" CS, rather than just let the 2 thread compete for it. Could you please explain the logic behind this?

Each worker Thread (i.e. the TThreadPoolThread instance) has it's own "Wait" semaphore (TCriticalSection instance).

The semaphore is owned by the main thread while the worker thread is supposed to do hold off, waiting to be assigned any work by setting the appropriate element of the "Tasks" property.

The semaphore is owned by the worker thread when it is working (as easily seen in the Execute procedure.

-Michael

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140918/df725348/attachment-0001.html>

Reply by email

Sven Barth
to Michael Schnell: They have nothing in common. TCriticalSection is a Semaphore (see Wikipedia) An event is…
"Michael Schnell" wrote 7 lines
On 09/18/2014 10:32 AM, Xiangrong Fang wrote: > > > > > ?I don't quite understand the logic or difference between critical

section ?

Show quoted text 9 lines
> > ?and events. They have nothing in common. TCriticalSection is a Semaphore (see Wikipedia) An event is a callback procedure ->

https://en.wikipedia.org/wiki/Callback_%28computer_programming%29

Sorry, but you will not be able to do such a project unless you

understand such basic computer science primitives.

You are wrong. A critical section is a mutex and an event in this context is a binary semaphore.

Regards,
Sven
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140918/47386193/attachment.html>

Reply by email

Michael Schnell
to Sven Barth
Sven Barth wrote
A critical section is a mutex

OK. (but a mutex is constructed from a semphore, anyway, even if this might be done in the OS). (I did this when doing my own special purpose multitasking OS (in C), some 20 Years ago.)

and an event in this context is a binary semaphore.

Here, you seem to be speaking of a "TEvent instance" not of a Object pascal language "Event" (such as "OnCreate") which is something completely unrelated (and which I provide as "OnReady" in the code I posted).

-Michael

Reply by email

Michael Schnell
to Xiangrong Fang: 2014-09-18 16:13 GMT+08:00 Michael Schnell : ?I don't quite understand the logic or…
Xiangrong Fang wrote
I don't quite understand the logic or difference between critical section and events.

Sorry for my previous rude reply.

Sven made me know that by "event" you did not mean an object pascal language "Event" (i.e. a callback), but a "TEvent instance".

Here, of course you can use both a TCriticalSection instance (i.e. a Mutex) as a TEvent Instance (i.e. a semaphore) for thread synchronizing.

(It's a shame that the creators of our brand of the Object Pascal Language once chose to invent new notions for commonly use concepts (Callback -> Event, Mutex -> CriticalSection, TEvent -> Semaphore, array of Boolean -> Set, ("object" for a kind of class (i.e. a type), instead of an instance of same is not used any more...)

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140918/6d6d3da8/attachment.html>

Reply by email

Mattias Gaertner
to Michael Schnell
Show quoted text 6 lines
[...] (It's a shame that the creators of our brand of the Object Pascal Language once chose to invent new notions for commonly use concepts (Callback -> Event, Mutex -> CriticalSection, TEvent -> Semaphore, array of Boolean -> Set, ("object" for a kind of class (i.e. a type), instead of an instance of same is not used any more...)

In Free Pascal an Event is a special callback, a CriticalSection is a special mutex, a TEvent is a special Semaphore, a Set is not an "array of boolean" and "object" has at least two different meanings.

Mattias

Reply by email

Michael Schnell
to Mattias Gaertner
Mattias Gaertner wrote
a Set is not an "array of boolean"

A set is an "array" (scientific English, not Pascal syntax) of bits (i.e. boolean values) supported by special operators.

(Remember: Boolean Algebra and Logical Algebra are mathematically equivalent).

The "Set" stuff is correctly done and "nice in Pascal, but in most cases I know, set type variables s are used not to represent real-world sets but real world arrays of logical values.

-Michael

Reply by email

Mattias Gaertner
to Michael Schnell: A set is an "array" (scientific English, not Pascal syntax) of bits (i.e. boolean values)…
On 09/18/2014 12:10 PM, Mattias Gaertner wrote: > a Set is not an "array of boolean" A set is an "array" (scientific English, not Pascal syntax) of bits (i.e. boolean values) supported by special operators.

On planet Melmac an "array of boolean" is a stew of cats. In Free Pascal a Set is not an "array of boolean". You can neither assign nor typecast them to each other.
Of course you are free to use any analogy you like to explain Sets and arrays, but then you should not blame Free Pascal, that your analogy does not work well.

Mattias

Reply by email

Xiangrong Fang
to Michael Schnell: Sorry for my previous rude reply. Sven made me know that by "event" you did not mean an…

2014-09-18 17:55 GMT+08:00 Michael Schnell :

Sven made me know that by "event" you did not mean an object pascal language "Event" (i.e. a callback), but a "TEvent instance".

Sorry, I mean *neither*. I mean an RTLEvent. See this page:

http://www.freepascal.org/docs-html/rtl/system/rtleventcreate.html

What I need help to understand is, repeating my previous email:

While using ACriticalSection.Acquire, two threads are COMPETING for a "token" to do certain task, hence you do not know WHICH thread eventually get that token, although statistically each thread have the same chance of getting the token in the long run.

While calling RTLeventWaitFor(), the calling thread gives up chance to run, blocked until another thread calls RTLeventSetEvent() to notify it.

If the above understanding is correct, then I believe only RTLEvent can "synchronize" threads, i.e., let them run in a *determined* order. While CriticalSection ONLY provide a way to protect a shared resource is not accessed simultaneously.

Alternatively, I have another "design":

procedure TMyThread.Execute;
begin
  while not Terminated do begin
    if FCondition = true then begin
      //do the job...
    end;
  end;
end;

In the code above, I do not use event or critical section is it enough to let this thread wait there, without wasting cpu time, until FCondition is set (externally by the main thread)?

Thanks!

Xiangrong
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140918/1580228a/attachment.html>

Reply by email

Michael Schnell
to Xiangrong Fang
Xiangrong Fang wrote
What I need help to understand is, repeating my previous email: ...

I think, in the other mail, I did explain how "Wait" is supposed to work in TThreadPool.

(And of course with some appropriate modifications of the source code, you can use RTLeventSetEvent instead of "TCriticalSection" if you like. )(

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140918/28621ade/attachment-0001.html>

Reply by email

Xiangrong Fang
to Michael Schnell

2014-09-18 19:34 GMT+08:00 Michael Schnell :

Show quoted text 5 lines
I think, in the other mail, I did explain how "Wait" is supposed to work in TThreadPool.

Initially, when the threadpool is created, Wait is hold by the main thread, so the worker just wait there, no problem, but after the worker thread get the CS, it started working, then RELEASE the CS.

This is when the problem arise: after worker release the CS, how do you ensure it is the MAIN thread who will get the CS next, NOT the worker thread again?

That is my question, which I don't think you answered.

Thanks,
Xiangrong
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140918/89b64fe4/attachment.html>

Reply by email

Michael Schnell
to Xiangrong Fang
Xiangrong Fang wrote 16 lines
2014-09-18 19:34 GMT+08:00 Michael Schnell < <mailto:>>: I think, in the other mail, I did explain how "Wait" is supposed to work in TThreadPool. Initially, when the threadpool is created, Wait is hold by the main thread, so the worker just wait there, no problem, but after the worker thread get the CS, it started working, then RELEASE the CS. This is when the problem arise: after worker release the CS, how do you ensure it is the MAIN thread who will get the CS next, NOT the worker thread again?

The Thread uses "synchronize(NotifyStopped)" to call a procedure that is run in the main thread (and it waits until this procedure is done). In this synchronized procedure, the main thread Acquires "wait" again, and hence the worker thread will block at the start of the next main loop turn.

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140918/3d483e7e/attachment.html>

Reply by email

Mark Morgan Lloyd
to Michael Schnell: A set is an "array" (scientific English, not Pascal syntax) of bits (i.e. boolean values)…
Michael Schnell wrote
On 09/18/2014 12:10 PM, Mattias Gaertner wrote: > a Set is not an "array of boolean" A set is an "array" (scientific English, not Pascal syntax) of bits (i.e. boolean values) supported by special operators.

I suggest calling it a vector (supported by special operators) since that sidesteps the question of whether it can be indexed.

/You/ might think that your command of scientific English is good enough, but in a public forum where there are plenty of users with less experience and poorer English using "array" in this context will cause problems.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Michael Schnell
to Xiangrong Fang: 2014-09-18 16:13 GMT+08:00 Michael Schnell : ?I don't quite understand the logic or…
Xiangrong Fang wrote
I don't quite understand the logic or difference between critical section and events.

Following your suggestion to use events (here meaning semahores) instead of critical sections (here meaning mutexes) I tried to modify my code to use TEvent (as same is Delphi compatible - or at least it does exist in Delphi as well).

Unfortunately I do not get this working. When I instantiate TEvents instead of TCriticalSections (and don't do much with same) the GUI freezes. In fact I do this in the "OnCreate" Event of the main Form and (not always but mostly) no child components are shown (but the close button [x] of the form still works.

I don't understand wow this can happen (svn versions of Lazarus and fpc).

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140919/d24abf3b/attachment.html>

Reply by email

Michael Schnell
to Michael Schnell
Michael Schnell wrote 5 lines
Following your suggestion to use events (here meaning semahores) instead of critical sections (here meaning mutexes) I tried to modify my code to use TEvent (as same is Delphi compatible - or at least it does exist in Delphi as well).

I got it working using TEvent instead of TCriticalSection.

As you need less calls to TEvent than were necessary with TCriticalSection this variant in fact is nicer.

-Michael

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140919/b8f9f82e/attachment.html>

Reply by email

Xiangrong Fang
to Michael Schnell: Following your suggestion to use events (here meaning semahores) instead of critical…

2014-09-19 18:23 GMT+08:00 Michael Schnell :

Show quoted text 8 lines
On 09/18/2014 10:32 AM, Xiangrong Fang wrote: Unfortunately I do not get this working. When I instantiate TEvents instead of TCriticalSections (and don't do much with same) the GUI freezes. In fact I do this in the "OnCreate" Event of the main Form and (not always but mostly) no child components are shown (but the close button [x] of the form still works.

As far as I tried, you cannot use RTLEventWaitFor in main thread, otherwise the gui will freeze. Don't know what you did...
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140919/6aefa931/attachment-0001.html>

Reply by email

Michael Schnell
to Xiangrong Fang
Xiangrong Fang wrote
As far as I tried, you cannot use RTLEventWaitFor in main thread, otherwise the gui will freeze.

Of course I did not do this. I used TEvent.Waitfor and I only used it in the Execute function of the worker Threads .

Supposedly the problem was that the Worker Threads I created already ran in a loop while the GUI constructed the Form and for an unknown reason the GUI Thread did not get enough time slices to ever get done with it's work.

Anyway, after correctly managing the worker Threads everything is fine.

I can post this version of the TThreadPool class here, if you might want to try it. I'd be very interested in knowing if the project works correctly on your (64 bit) systems.

-Michael

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140919/1f9feaec/attachment.html>

Reply by email

Sven Barth
to Xiangrong Fang: 2014-09-19 18:23 GMT+08:00 Michael Schnell : As far as I tried, you cannot use…
"Xiangrong Fang" wrote 7 lines
2014-09-19 18:23 GMT+08:00 Michael Schnell : > > On 09/18/2014 10:32 AM, Xiangrong Fang wrote: > > Unfortunately I do not get this working. When I instantiate TEvents

instead of TCriticalSections (and don't do much with same) the GUI freezes. In fact I do this in the "OnCreate" Event of the main Form and (not always but mostly) no child components are shown (but the close button [x] of the form still works.

As far as I tried, you cannot use RTLEventWaitFor in main thread,

otherwise the gui will freeze. Don't know what you did...

Of course you can use RTLEventWaitFor (or other blocking functions) inside the main thread, but then you need to he aware if the consequences: when the main thread is blocked, then the GUI will be blocked as well, because the GUI is handled by the main thread only. And a single thread can't do blocking and running at once ;)

Regards,
Sven
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140919/e7b3f339/attachment.html>

Reply by email

Michael Schnell
to Michael Schnell: Of course I did not do this. I used TEvent.Waitfor and I only used it in the Execute…
Michael Schnell wrote
I can post this version of the TThreadPool class here, if you might want to try it. I'd be very interested in knowing if the project works correctly on your (64 bit) systems.

I set up a virtual Box with 64 Bit Debian, installed the released 64 Bit version of FPC (but not Lazarus) and modified the example code to be able to be compiled as well with as without GUI.

So I was able to test TThreadPool on 64 Bit.

Works nicely.

-Michael
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20140926/e8794789/attachment.html>

Reply by email