Sign in Join

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

Mailing lists / lazarus / 2012-03

Threads

24 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

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

Antonio Fortuny

Hi folks.

Wen launching a thread, the process responsible for the thread object creation and the call to TThread.Start and the thread EXECUTE procedure, run in parallel. That's why the SYNCHRONIZE procedure exists and that the developer has to pay attention to not share code between threads. So far, so good.
Now imagine that the EXECUTE procedure of a thread creates a useful object (TMyObject) with properties and methods. This thread is launched half a dozen times to process half a dozen simultaneous operations. My question is:
How the properties and methods of the TMyObject created in every launched thread are they managed from one thread to another. As far as the data segment is concerned, no problem, I guess that every instance of the TMyObject has its own data in its thread address space: no mix. But what about the code and the local methods stack: will it be shared ? And if answer is yes, to what should I take care ?

The question is far from trivial: I try to keep the EXECUTE procedure as small as possible and spread the code and data over a number of specialized units avoiding to load the EXECUTE procedure stack with heavy data ans structures.

I apologize if my question doesn't sound very clear, but it's not even clear in my mind :-[

Antonio.

Reply by email

Mattias Gaertner
to Antonio Fortuny

Antonio Fortuny hat am 22. M?rz 2012 um 15:32
geschrieben:

Show quoted text 17 lines
Hi folks. Wen launching a thread, the process responsible for the thread object creation and the call to TThread.Start and the thread EXECUTE procedure, run in parallel. That's why the SYNCHRONIZE procedure exists and that the developer has to pay attention to not share code between threads. So far, so good. Now imagine that the EXECUTE procedure of a thread creates a useful object (TMyObject) with properties and methods. This thread is launched half a dozen times to process half a dozen simultaneous operations. My question is: How the properties and methods of the TMyObject created in every launched thread are they managed from one thread to another. As far as the data segment is concerned, no problem, I guess that every instance of the TMyObject has its own data in its thread address space: no mix. But what about the code and the local methods stack: will it be shared ? And if answer is yes, to what should I take care ?

Each thread has its own stack.
All threads share the same address space and the same heap. Objects (here: class instances) are created on the heap. The heap is thread safe.
The data segment is for constants. They are shared.

Show quoted text 8 lines
The question is far from trivial: I try to keep the EXECUTE procedure as small as possible and spread the code and data over a number of specialized units avoiding to load the EXECUTE procedure stack with heavy data ans structures. I apologize if my question doesn't sound very clear, but it's not even clear in my mind :-[

Mattias
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20120322/8c0c3d25/attachment.html>

Reply by email

Sven Barth
to Antonio Fortuny: Hi folks. Wen launching a thread, the process responsible for the thread object creation…
Antonio Fortuny wrote 25 lines
Hi folks. Wen launching a thread, the process responsible for the thread object creation and the call to TThread.Start and the thread EXECUTE procedure, run in parallel. That's why the SYNCHRONIZE procedure exists and that the developer has to pay attention to not share code between threads. So far, so good. Now imagine that the EXECUTE procedure of a thread creates a useful object (TMyObject) with properties and methods. This thread is launched half a dozen times to process half a dozen simultaneous operations. My question is: How the properties and methods of the TMyObject created in every launched thread are they managed from one thread to another. As far as the data segment is concerned, no problem, I guess that every instance of the TMyObject has its own data in its thread address space: no mix. But what about the code and the local methods stack: will it be shared ? And if answer is yes, to what should I take care ? The question is far from trivial: I try to keep the EXECUTE procedure as small as possible and spread the code and data over a number of specialized units avoiding to load the EXECUTE procedure stack with heavy data ans structures. I apologize if my question doesn't sound very clear, but it's not even clear in my mind :-[

I don't know whether I understood your question correctly, but I'll try to answer:
* Each thread has it's own stack space, so objects/data located on the stack is (normally) not shared between threads (an exception for example are writeable local consts, because they act like static variables)
* The part of the executable which runs between "begin ... end." in the main project file is a thread itself (also called "main thread"), so one does not need to differentiate between threads started by you and the thread started by the operating system at process start
* The Heap (the area of the memory where e.g. object instances and data allocated with New/GetMem resides) is shared between all threads. So you need to be careful if you create an object in thread A and change it in thread B (and thread A as well). But if you create an object in method X that is called by thread A and thread B and you never pass the instance to another thread you have no problem, because no other thread then knows the reference to this object.

I hope this clarifies things a bit. Feel free to ask back if you need to.

Regards,
Sven

Reply by email

Michael Schnell
to Antonio Fortuny: Hi folks. Wen launching a thread, the process responsible for the thread object creation…

Besides what the other said a very basic comment.

The location where an object is defined (i.e. within a TThread enabled unit) or who created it (the main line code or the thread code) does not matter. The Concept of classes, objects and instances is a matter of memory allocation and pointers and not a concept of program flow. same is absolutely independent. You can use one instance of a class in one thread and another one in another thread. You can create an instance in one thread and call its procedures and properties by another one. (BTW this results in the fact that its very hard to define something like "Thread-safe" for a class).

In fact you need to look exactly how the program flow of each thread is before deciding what code needs to be protected regarding mutual accesses by threads. Just looking at the objects does not help much, Looking at the point where an object is created does not

Reply by email

Antonio Fortuny
to Mattias Gaertner: Antonio Fortuny hat am 22. M?rz 2012 um 15:32 geschrieben: Each thread has its own stack.

Le 22/03/2012 16:20, Mattias Gaertner a ?crit :

Show quoted text 10 lines
Each thread has its own stack. All threads share the same address space and the same heap. Objects (here: class instances) are created on the heap. The heap is thread safe. The data segment is for constants. They are shared.

Le 22/03/2012 17:10, Michael Schnell a ?crit :

Show quoted text 11 lines
Besides what the other said a very basic comment. The location where an object is defined (i.e. within a TThread enabled unit) or who created it (the main line code or the thread code) does not matter. The Concept of classes, objects and instances is a matter of memory allocation and pointers and not a concept of program flow. same is absolutely independent. You can use one instance of a class in one thread and another one in another thread. You can create an instance in one thread and call its procedures and properties by another one. (BTW this results in the fact that its very hard to define something like "Thread-safe" for a class).

Thanks to you all .
Trying to be as much clear as possible, there are some sentences:

Assuming this few statements (aka my own rules when writing thread's code): a. all thread code+data are encapsulated into a TThread object b. "Thread safe" means that there is no overlap of data references from thread to thread, the main thread inclusive, and that no references are passed outside the thread's control from thread to thread (by the means of the owner or global vars for instance)
c. the thread creator does not interfere in any way with the thread's data and methods as soon as the thread has been started (Terminated execpted of course)
d. no function neither procedure calls are made to any function or procedure defined outside of the thread control (aka self defined methods)

Do you all agree on the following asserts:
1. All variables in the thread definition (TThread's private, protected and public variables) are "Thread safe" BUT are accessible to the thread creator
2. an instance of an object (aka TObject descendant) created into the thread's EXECUTE procedure is invisible to all other instances of the same object whichever the creator could be (the same thread or other threads created with the same thread definition object) and to other thread object instances, even when the reference variable of the created object is defined into the thread vars (see 1.) provided that all object methods do not call any function or procedure outside of the object methods.
3. all variables described in the VAR part of the EXECUTE procedure are "Thread safe" (seems obvious)
4. all local variables and constants defined into local Thread object methods are "Thread safe" (they are defined into each thread stack for the vars and the heap for constants)
5. all useful code a thread needs should be encapsultated into a TObject descendant and instantiated within the thread's space.
6. all methods defined in the thread's definition, aprat from the EXECUTE procedure (obvious !), run into the thread creator space (the one which instantiates the thread, aka does something like wThread := TMyThread.Create (False) )

This list is (certainly) not exhausted.

Antonio.

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

Reply by email

Sven Barth
to Antonio Fortuny
Antonio Fortuny wrote 37 lines
Le 22/03/2012 16:20, Mattias Gaertner a ?crit : > > Each thread has its own stack. > > All threads share the same address space and the same heap. > > Objects (here: class instances) are created on the heap. The heap is > thread safe. > > The data segment is for constants. They are shared. > Le 22/03/2012 17:10, Michael Schnell a ?crit : > Besides what the other said a very basic comment. > > The location where an object is defined (i.e. within a TThread enabled > unit) or who created it (the main line code or the thread code) does > not matter. The Concept of classes, objects and instances is a matter > of memory allocation and pointers and not a concept of program flow. > same is absolutely independent. You can use one instance of a class in > one thread and another one in another thread. You can create an > instance in one thread and call its procedures and properties by > another one. (BTW this results in the fact that its very hard to > define something like "Thread-safe" for a class). Thanks to you all . Trying to be as much clear as possible, there are some sentences: Assuming this few statements (aka my own rules when writing thread's code): a. all thread code+data are encapsulated into a TThread object b. "Thread safe" means that there is no overlap of data references from thread to thread, the main thread inclusive, and that no references are passed outside the thread's control from thread to thread (by the means of the owner or global vars for instance) c. the thread creator does not interfere in any way with the thread's data and methods as soon as the thread has been started (Terminated execpted of course) d. no function neither procedure calls are made to any function or procedure defined outside of the thread control (aka self defined methods)

Ok, I hereby assume the above as given.

Do you all agree on the following asserts: 1. All variables in the thread definition (TThread's private, protected and public variables) are "Thread safe" BUT are accessible to the thread creator

Yes (though the private vars aren't available to the thread creator if the creator and the definition of your TThread descendant reside in different units ;) )

Show quoted text 7 lines
2. an instance of an object (aka TObject descendant) created into the thread's EXECUTE procedure is invisible to all other instances of the same object whichever the creator could be (the same thread or other threads created with the same thread definition object) and to other thread object instances, even when the reference variable of the created object is defined into the thread vars (see 1.) provided that all object methods do not call any function or procedure outside of the object methods.

If I've understood that correctly: yes

3. all variables described in the VAR part of the EXECUTE procedure are "Thread safe" (seems obvious)

Yes

4. all local variables and constants defined into local Thread object methods are "Thread safe" (they are defined into each thread stack for the vars and the heap for constants)

It's true for variables. Local constants are defined in a section of the executable, so if you have writable constants enabled (only then it's a problem) and you write to these constants then the change will be reflected in other constants as well. If you don't write to the constants than they are safe.

5. all useful code a thread needs should be encapsultated into a TObject descendant and instantiated within the thread's space.

Note necessarily. You can also call global procedures/functions that don't rely on global state (e.g. IntToStr, etc.). If you want to call functions/procedures that rely on the state (e.g. some registration systems for classes) you'll need to synchronize the access.

6. all methods defined in the thread's definition, aprat from the EXECUTE procedure (obvious !), run into the thread creator space (the one which instantiates the thread, aka does something like wThread := TMyThread.Create (False) )

I don't know whether I understood you correctly, but if you have this:

=== example begin ===

type
   TTestThread = class(TThread)
   protected
     procedure Execute; override;
   public
     procedure DoSomething;
   end;
procedure TTestThread.Execute;
begin
   DoSomething;
end;
procedure TTestThread.DoSomething;
begin
   Writeln('Something');
end;
begin
   with TTestThread.Create(True) do begin
     FreeOnTerminate := True;
     Start;
   end;
end.

=== example end ===

Then (to my understandment of your assertion) your assertion is wrong, because DoSomething is (although it is public) only called in context of Execute (Note: Not that you should make such a method public if you don't need to, but this is merely an example).

Regards,
Sven

Reply by email

Hans-Peter Diettrich
to Antonio Fortuny: Le 22/03/2012 16:20, Mattias Gaertner a ?crit : Le 22/03/2012 17:10, Michael Schnell a…
Show quoted text 13 lines
Trying to be as much clear as possible, there are some sentences: Assuming this few statements (aka my own rules when writing thread's code): a. all thread code+data are encapsulated into a TThread object b. "Thread safe" means that there is no overlap of data references from thread to thread, the main thread inclusive, and that no references are passed outside the thread's control from thread to thread (by the means of the owner or global vars for instance) c. the thread creator does not interfere in any way with the thread's data and methods as soon as the thread has been started (Terminated execpted of course) d. no function neither procedure calls are made to any function or procedure defined outside of the thread control (aka self defined methods)

Looks good :-)

Do you all agree on the following asserts: 1. All variables in the thread definition (TThread's private, protected and public variables) are "Thread safe" BUT are accessible to the thread creator

The OPL visibility rules apply. Public members are accessible by everybody, others only from inside the unit where the thread class is declared. As long as the thread creator doesn't export the thread object, nobody else can access it, of course.

5. all useful code a thread needs should be encapsultated into a TObject descendant and instantiated within the thread's space.

This can all be implemented in the derived TThread class.

6. all methods defined in the thread's definition, aprat from the EXECUTE procedure (obvious !), run into the thread creator space (the one which instantiates the thread, aka does something like wThread := TMyThread.Create (False) )

Every procedure or method runs in the context of its *caller*. Everything called from the thread's Execute method executes in the thread context (stack, threadvars).

DoDi

Reply by email

Antonio Fortuny
to Sven Barth: Ok, I hereby assume the above as given. Yes (though the private vars aren't available to…

Thanks Sven, I really appreciate.

Le 23/03/2012 10:59, Sven Barth a ?crit :

Show quoted text 77 lines
Am 23.03.2012 10:25, schrieb Antonio Fortuny: > Le 22/03/2012 16:20, Mattias Gaertner a ?crit : >> >> Each thread has its own stack. >> >> All threads share the same address space and the same heap. >> >> Objects (here: class instances) are created on the heap. The heap is >> thread safe. >> >> The data segment is for constants. They are shared. >> > Le 22/03/2012 17:10, Michael Schnell a ?crit : >> Besides what the other said a very basic comment. >> >> The location where an object is defined (i.e. within a TThread enabled >> unit) or who created it (the main line code or the thread code) does >> not matter. The Concept of classes, objects and instances is a matter >> of memory allocation and pointers and not a concept of program flow. >> same is absolutely independent. You can use one instance of a class in >> one thread and another one in another thread. You can create an >> instance in one thread and call its procedures and properties by >> another one. (BTW this results in the fact that its very hard to >> define something like "Thread-safe" for a class). > Thanks to you all . > Trying to be as much clear as possible, there are some sentences: > > Assuming this few statements (aka my own rules when writing thread's > code): > a. all thread code+data are encapsulated into a TThread object > b. "Thread safe" means that there is no overlap of data references from > thread to thread, the main thread inclusive, and that no references are > passed outside the thread's control from thread to thread (by the means > of the owner or global vars for instance) > c. the thread creator does not interfere in any way with the thread's > data and methods as soon as the thread has been started (Terminated > execpted of course) > d. no function neither procedure calls are made to any function or > procedure defined outside of the thread control (aka self defined > methods) Ok, I hereby assume the above as given. > Do you all agree on the following asserts: > 1. All variables in the thread definition (TThread's private, protected > and public variables) are "Thread safe" BUT are accessible to the thread > creator Yes (though the private vars aren't available to the thread creator if the creator and the definition of your TThread descendant reside in different units ;) ) > 2. an instance of an object (aka TObject descendant) created into the > thread's EXECUTE procedure is invisible to all other instances of the > same object whichever the creator could be (the same thread or other > threads created with the same thread definition object) and to other > thread object instances, even when the reference variable of the created > object is defined into the thread vars (see 1.) provided that all object > methods do not call any function or procedure outside of the object > methods. If I've understood that correctly: yes > 3. all variables described in the VAR part of the EXECUTE procedure are > "Thread safe" (seems obvious) Yes > 4. all local variables and constants defined into local Thread object > methods are "Thread safe" (they are defined into each thread stack for > the vars and the heap for constants) It's true for variables. Local constants are defined in a section of the executable, so if you have writable constants enabled (only then it's a problem) and you write to these constants then the change will be reflected in other constants as well. If you don't write to the constants than they are safe.

Well, when I define a *const* anywhere in a program it is a *constant* actually otherwise I use a var. In this case I guess than there is no problem for any thread to read a constant whatever the context could be

Show quoted text 8 lines
> 5. all useful code a thread needs should be encapsultated into a TObject > descendant and instantiated within the thread's space. Note necessarily. You can also call global procedures/functions that don't rely on global state (e.g. IntToStr, etc.). If you want to call functions/procedures that rely on the state (e.g. some registration systems for classes) you'll need to synchronize the access.

Is it more accurate to state that any global procedure or function could be called by any thread as far as the called code does not reference anything outside itself apart from other global code considered as "Tread safe" too or constants. For example StrToIntDef.

Show quoted text 41 lines
> 6. all methods defined in the thread's definition, aprat from the > EXECUTE procedure (obvious !), run into the thread creator space (the > one which instantiates the thread, aka does something like wThread := > TMyThread.Create (False) ) I don't know whether I understood you correctly, but if you have this: === example begin === type TTestThread = class(TThread) protected procedure Execute; override; public procedure DoSomething; end; procedure TTestThread.Execute; begin DoSomething; end; procedure TTestThread.DoSomething; begin Writeln('Something'); end; begin with TTestThread.Create(True) do begin FreeOnTerminate := True; Start; end; end. === example end === Then (to my understandment of your assertion) your assertion is wrong, because DoSomething is (although it is public) only called in context of Execute (Note: Not that you should make such a method public if you don't need to, but this is merely an example).

Very nice indeed. You did understand, really.

Show quoted text 10 lines
Regards, Sven -- _______________________________________________ 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/20120323/8a44fddc/attachment.html>

Reply by email

Antonio Fortuny
to Hans-Peter Diettrich: Looks good :-) The OPL visibility rules apply. Public members are accessible by…

Many thanks Dodi.

Antonio.

Le 23/03/2012 10:59, Hans-Peter Diettrich a ?crit :

Show quoted text 29 lines
Antonio Fortuny schrieb: > Trying to be as much clear as possible, there are some sentences: > > Assuming this few statements (aka my own rules when writing thread's > code): > a. all thread code+data are encapsulated into a TThread object > b. "Thread safe" means that there is no overlap of data references > from thread to thread, the main thread inclusive, and that no > references are passed outside the thread's control from thread to > thread (by the means of the owner or global vars for instance) > c. the thread creator does not interfere in any way with the thread's > data and methods as soon as the thread has been started (Terminated > execpted of course) > d. no function neither procedure calls are made to any function or > procedure defined outside of the thread control (aka self defined > methods) Looks good :-) > Do you all agree on the following asserts: > 1. All variables in the thread definition (TThread's private, > protected and public variables) are "Thread safe" BUT are accessible > to the thread creator The OPL visibility rules apply. Public members are accessible by everybody, others only from inside the unit where the thread class is declared. As long as the thread creator doesn't export the thread object, nobody else can access it, of course.

I agree with you that the assertion could be more precise when talking about object members visibility. But we are talking abount OOP, aren't we ? 8-)

Show quoted text 6 lines
> 5. all useful code a thread needs should be encapsultated into a > TObject descendant and instantiated within the thread's space. This can all be implemented in the derived TThread class.

So, building an object around this utility code does not enlarge thread safety ?

Show quoted text 9 lines
> 6. all methods defined in the thread's definition, aprat from the > EXECUTE procedure (obvious !), run into the thread creator space > (the one which instantiates the thread, aka does something like > wThread := TMyThread.Create (False) ) Every procedure or method runs in the context of its *caller*. Everything called from the thread's Execute method executes in the thread context (stack, threadvars).

Sounds very clear. Big idea using few words. I appeciate.

Show quoted text 10 lines
DoDi -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply by email

Michael Schnell
to Antonio Fortuny: Le 22/03/2012 16:20, Mattias Gaertner a ?crit : Le 22/03/2012 17:10, Michael Schnell a…

Your concept of threads does not really hold.

Regarding the thread object (TThread descendant) instance itself:

It's creator is called by some thread (usually the project's main thread) but of course not by the thread that is going to be created.

Some of it's properties and functions are _supposed_ to be used by the thread it owns (e.g. "Terminated")

Some of it's properties and functions are _supposed_ to be used by other threads (e.g. "Terminate")

It depends on the user code what self-created additional functions and properties are to be used by whom and if they can be considered to be thread save.

Same holds for stuff created outside of the thread unit, but supposed to be used by the thread ("Execute" procedure).

(There is no simplified concept.)

-Michael

Reply by email

Sven Barth
to Michael Schnell
Michael Schnell wrote 21 lines
Your concept of threads does not really hold. Regarding the thread object (TThread descendant) instance itself: It's creator is called by some thread (usually the project's main thread) but of course not by the thread that is going to be created. Some of it's properties and functions are _supposed_ to be used by the thread it owns (e.g. "Terminated") Some of it's properties and functions are _supposed_ to be used by other threads (e.g. "Terminate") It depends on the user code what self-created additional functions and properties are to be used by whom and if they can be considered to be thread save. Same holds for stuff created outside of the thread unit, but supposed to be used by the thread ("Execute" procedure). (There is no simplified concept.)

You know that he wrote the following, stressing the part in the parenthesis:

Assuming this few statements (aka my own rules when writing thread's code):

Thus he is fully aware that this is not a general concept, but only his own, "enforced" by himself.

Regards,
Sven

Reply by email

Antonio Fortuny
to Sven Barth

Le 23/03/2012 12:18, Sven Barth a ?crit :

Show quoted text 31 lines
Am 23.03.2012 12:02, schrieb Michael Schnell: > Your concept of threads does not really hold. > > Regarding the thread object (TThread descendant) instance itself: > > It's creator is called by some thread (usually the project's main > thread) but of course not by the thread that is going to be created. > > Some of it's properties and functions are _supposed_ to be used by the > thread it owns (e.g. "Terminated") > > Some of it's properties and functions are _supposed_ to be used by other > threads (e.g. "Terminate") > > It depends on the user code what self-created additional functions and > properties are to be used by whom and if they can be considered to be > thread save. > > Same holds for stuff created outside of the thread unit, but supposed to > be used by the thread ("Execute" procedure). > > (There is no simplified concept.) You know that he wrote the following, stressing the part in the parenthesis: > Assuming this few statements (aka my own rules when writing thread's > code): Thus he is fully aware that this is not a general concept, but only his own, "enforced" by himself.

That's the point. In fact I'm used to write thead code since a long time ago but without a formal guideline, only guessing what the OS is supposed to do and manage. This time I'm trying to describe in a more formal way the rules to follow, whose main purpose is to avoid problems since the very beginning. Basically you all three (Yourself, Michael and Dodi) have stated the same mechanisms which are the ones I guessed but not being sure they were correct. Now I'm a lot more confident on what is going on when multiple thread instances are running and this was the majoir point I wanted to focus on.
This will help me to figure out how things really happen and to begin the drawing of an internal document stating how to write safe threads within the context of our company. Because Lazarus (Win & Linux, 32-64 bit) is highly concerned, I posted my question in this thread (8-) ).

As a last conclusion all this leads me to prefer the writing of objects which will contain the thread functionality instead of writing internal thread methods. The big advantage is maintenance: it is easier when the code is spread over a series of specialized units which can focus on a particular side of the job (i.e. basic object used by the thread). Second advantage is the ability to use DUnit testing outside of the context of a thread. Another advantage is the possibility to reuse the objects code in other applications. I mean not specific thread code but general purpose code. As a mattrer of disadvantage I can point out the overhead introduced by the object internal code itself in terms of memory and process time. But it is immediately related to the base object itself. In any case, the former rules I've stated are still true.

Anyway, is seems clear to me that every thread code will be developed around ist particular concept and objectives. Michael is right too when he writes that there is no simplified concept.

Again, many thanks to all of you.

Antonio.

Show quoted text 10 lines
Regards, Sven -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply by email

Michael Schnell
to Antonio Fortuny

It's rather straight forward to do completely distinct threads.

The tricky part starts, when the threads need to communicate (which always is necessary) and thus share some data.

Here you need to be aware of several things:

- the components and functions in the LCL and RTL usually are not thread-save (and there is no documentation on in what way they are "partly thread safe) e.g.
- - Many simple functions like IntToStr() seem to thread safe, but this is not documented.
- - You can't use any function that accesses the GUI in another thread but the main thread.
- - You can happily use multiple instances of TList in multiple threads as long as each a single instance is not used by multiple threads.
- - You can use the same instance of TList in multiple threads if you use a TCtriticalSection (e.g. one for each instance of TList) do block concurrent accesses.
- - AFAIK, the way TThreadList is used with multiple threads is documented.

- To have a worker thread communicate with the main thread (i.e. to have it use the GUI in any way) you can use TThread.Synchronize. Downside: The thread waits until any scheduled main thread activity is done before entering the synchronized code (might last forever). It only goes on working when the synchronized code is done.

- To trigger a main thread activity without having to wait for the main thread you can use Application.QueueAsnycCall.

- The functionality of TThread.Synchronize and
Application.QueuAsyncCall is not available in all Widget Types (see Compile-Options -> Build Modes). It is verified to work decently in GTK and Win32 (and supposedly QT, but I did not check this myself).

-Michael

Reply by email

Antonio Fortuny
to Michael Schnell

Le 23/03/2012 15:24, Michael Schnell a ?crit :

Show quoted text 36 lines
It's rather straight forward to do completely distinct threads. The tricky part starts, when the threads need to communicate (which always is necessary) and thus share some data. Here you need to be aware of several things: - the components and functions in the LCL and RTL usually are not thread-save (and there is no documentation on in what way they are "partly thread safe) e.g. - - Many simple functions like IntToStr() seem to thread safe, but this is not documented. - - You can't use any function that accesses the GUI in another thread but the main thread. - - You can happily use multiple instances of TList in multiple threads as long as each a single instance is not used by multiple threads. - - You can use the same instance of TList in multiple threads if you use a TCtriticalSection (e.g. one for each instance of TList) do block concurrent accesses. - - AFAIK, the way TThreadList is used with multiple threads is documented. - To have a worker thread communicate with the main thread (i.e. to have it use the GUI in any way) you can use TThread.Synchronize. Downside: The thread waits until any scheduled main thread activity is done before entering the synchronized code (might last forever). It only goes on working when the synchronized code is done. - To trigger a main thread activity without having to wait for the main thread you can use Application.QueueAsnycCall. - The functionality of TThread.Synchronize and Application.QueuAsyncCall is not available in all Widget Types (see Compile-Options -> Build Modes). It is verified to work decently in GTK and Win32 (and supposedly QT, but I did not check this myself).

All those are the basics that I apply since I'm busy writing threads code. I already make use of Critical sections and events lock some external resources (log files for instance) and I avoid to have any thread code using any kind of GUI. All thread code I write, is contained in OS services or very specialized programs having no , thanks for precisions.

Antonio.

Show quoted text 8 lines
-Michael -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply by email

Sven Barth
to Antonio Fortuny
Antonio Fortuny wrote 46 lines
Le 23/03/2012 15:24, Michael Schnell a ?crit : > It's rather straight forward to do completely distinct threads. > > The tricky part starts, when the threads need to communicate (which > always is necessary) and thus share some data. > > Here you need to be aware of several things: > > - the components and functions in the LCL and RTL usually are not > thread-save (and there is no documentation on in what way they are > "partly thread safe) e.g. > - - Many simple functions like IntToStr() seem to thread safe, but > this is not documented. > - - You can't use any function that accesses the GUI in another thread > but the main thread. > - - You can happily use multiple instances of TList in multiple > threads as long as each a single instance is not used by multiple > threads. > - - You can use the same instance of TList in multiple threads if you > use a TCtriticalSection (e.g. one for each instance of TList) do block > concurrent accesses. > - - AFAIK, the way TThreadList is used with multiple threads is > documented. > > - To have a worker thread communicate with the main thread (i.e. to > have it use the GUI in any way) you can use TThread.Synchronize. > Downside: The thread waits until any scheduled main thread activity is > done before entering the synchronized code (might last forever). It > only goes on working when the synchronized code is done. > > - To trigger a main thread activity without having to wait for the > main thread you can use Application.QueueAsnycCall. > > - The functionality of TThread.Synchronize and > Application.QueuAsyncCall is not available in all Widget Types (see > Compile-Options -> Build Modes). It is verified to work decently in > GTK and Win32 (and supposedly QT, but I did not check this myself). All those are the basics that I apply since I'm busy writing threads code. I already make use of Critical sections and events lock some external resources (log files for instance) and I avoid to have any thread code using any kind of GUI. All thread code I write, is contained in OS services or very specialized programs having no GUI at all. Anyway, thanks for precisions.

Just for the case you understood that wrong: There is no pricincipal problem of threads running in a GUI app. The problems arise only if you access some visual component (e.g. change the Caption of a Label) without using Synchronize. If you either use Synchronize or your threads don't access the GUI directly, then you won't have problems with them.

E.g. the scanning of the Free Pascal source directory at the first start of Lazarus (or when you change the source directory) is done using a thread.

Regards,
Sven

Reply by email

Hans-Peter Diettrich
to Antonio Fortuny: Many thanks Dodi. Antonio. Le 23/03/2012 10:59, Hans-Peter Diettrich a ?crit : I agree…
Show quoted text 6 lines
>> 5. all useful code a thread needs should be encapsultated into a >> TObject descendant and instantiated within the thread's space. > > This can all be implemented in the derived TThread class. So, building an object around this utility code does not enlarge thread safety ?

Not really. Thread safe code must not access global variables, neither directly nor indirectly in called subroutines. The latter cannot be assured by wrapping the code in a class. See also:

Show quoted text 9 lines
>> 6. all methods defined in the thread's definition, aprat from the >> EXECUTE procedure (obvious !), run into the thread creator space >> (the one which instantiates the thread, aka does something like >> wThread := TMyThread.Create (False) ) > > Every procedure or method runs in the context of its *caller*. > Everything called from the thread's Execute method executes in the > thread context (stack, threadvars). Sounds very clear. Big idea using few words. I appeciate.

:-)

DoDi

Reply by email

Antonio Fortuny
to Sven Barth: Just for the case you understood that wrong: There is no pricincipal problem of threads…

All those are the basics that I apply since I'm busy writing threads

Show quoted text 13 lines
> code. I already make use of Critical sections and events lock some > external resources (log files for instance) and I avoid to have any > thread code using any kind of GUI. All thread code I write, is contained > in OS services or very specialized programs having no GUI at all. > > Anyway, thanks for precisions. Just for the case you understood that wrong: There is no pricincipal problem of threads running in a GUI app. The problems arise only if you access some visual component (e.g. change the Caption of a Label) without using Synchronize. If you either use Synchronize or your threads don't access the GUI directly, then you won't have problems with them.

Ok, sorry, confusing sentence. I mean that I'm aware of Synchronize use (thanks to multiple crashes ;-) ) and interfacing threads with other threads or processes (I use a shared Q of my own with, of course, critical section, signals and events, etc to be as much independent of OS as possible but this is another point) and I use them sometimes when I write some thread code in a GUI application. No problem with that. In my mind I was thinking on services which do not have (but can have) a GUI.

Again, I think it is useful to be as precise and accurate as possible on this matters.

Thanks Sven.

Show quoted text 15 lines
E.g. the scanning of the Free Pascal source directory at the first start of Lazarus (or when you change the source directory) is done using a thread. Regards, Sven -- _______________________________________________ Lazarus mailing list http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply by email

Michael Schnell
to Antonio Fortuny: Le 23/03/2012 15:24, Michael Schnell a ?crit : All those are the basics that I apply…
Antonio Fortuny wrote 6 lines
All thread code I write, is contained in OS services or very specialized programs having no this issue might be a problem (it was for me): > - The functionality of TThread.Synchronize and > Application.QueuAsyncCall is not available in all Widget Types (see > Compile-Options -> Build Modes). It is verified to work decently in > GTK and Win32 (and supposedly QT, but I did not check this myself).

Using any of the non standard PC GUI aware Lazarus Widget types, you can't have a main thread and thus not "event driven programming" and thus no events that are scheduled by threads.

-Michael

Reply by email

Lukasz Sokol
to Michael Schnell
Michael Schnell wrote 6 lines
BTW.: Do you know this ? www.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-1.pdf -Michael O:-)

Cool especially the last sentence...
"
Threads must be relegated to the engine room of computing, to be suffered only by expert technology providers
"
L.

Reply by email

Mark Morgan Lloyd
to Lukasz Sokol
Lukasz Sokol wrote 12 lines
On 23/03/2012 16:10, Michael Schnell wrote: > BTW.: Do you know this ? > > www.eecs.berkeley.edu/Pubs/TechRpts/2006/EECS-2006-1.pdf > > -Michael O:-) > Cool especially the last sentence... " Threads must be relegated to the engine room of computing, to be suffered only by expert technology providers "

Equally significant, in my view, is the second sentence:

"Languages require little or no syntactic changes to support threads, and operating systems and architectures have evolved to efficiently support them."

followed by

"[Threads] discard the most essential and appealing properties of sequential computation: understandability, predictability, and determinism. Threads, as a model of computation, are wildly nondeterministic,"

In short, however he dresses up his argument with references to e.g. Occam, he's writing from the point of view of a computer scientist with no experience of embedded systems etc. where implementors are experienced in handling asynchronous and nested interrupts, and probably with no experience of Delphi and Lazarus which at the time of writing provided a fairly effective threading model.

Allowing that this was written more than six years ago, it would be interesting to know whether he's modified his position now that POSIX threads are widely and reliably implemented.

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

Lukasz Sokol
to Mark Morgan Lloyd
Mark Morgan Lloyd wrote 25 lines
>> > Cool especially the last sentence... " Threads must be relegated to > the engine room of computing, to be suffered only by expert > technology providers " Equally significant, in my view, is the second sentence: "Languages require little or no syntactic changes to support threads, and operating systems and architectures have evolved to efficiently support them." followed by "[Threads] discard the most essential and appealing properties of sequential computation: understandability, predictability, and determinism. Threads, as a model of computation, are wildly nondeterministic," In short, however he dresses up his argument with references to e.g. Occam, he's writing from the point of view of a computer scientist with no experience of embedded systems etc. where implementors are experienced in handling asynchronous and nested interrupts, and probably with no experience of Delphi and Lazarus which at the time of writing provided a fairly effective threading model.

Should have put a :O emoticon after my 'cool' sentence...

Allowing that this was written more than six years ago, it would be interesting to know whether he's modified his position now that POSIX threads are widely and reliably implemented.

And multi-threaded and multi-cored cpu's available more than 6 years ago too.

(though truth be said, from looking at the lkml discussions, writing smp and rt aware scheduler is by no means easy without compromising on any side of it...)

L.

Reply by email