Sign in Join

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

Mailing lists / fpc-pascal / 2014-10

Is TFPList thread safe?

18 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

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

Xiangrong Fang

Hi,

I would like to know if TFPList is thread-safe or not? And if I make a component thread-safe by using critical sections etc. Is the performance penalty noticeable?

Thanks.

Xiangrong

Michael Van Canneyt
to Xiangrong Fang
Xiangrong Fang wrote
Hi, I would like to know if TFPList is thread-safe or not? And if I make a component thread-safe by using critical sections etc. Is the performance penalty noticeable? 

TFPList is not thread-safe. You need to use TThreadList if you want a thread-safe list.

Critical sections use OS calls, so there is always a performance penalty.

Michael.

Michael Schnell
to Xiangrong Fang: I would like to know if TFPList is thread-safe or not? And if I make a component…
Xiangrong Fang wrote 5 lines
Hi, I would like to know if TFPList is thread-safe or not? And if I make a component thread-safe by using critical sections etc. Is the performance penalty noticeable?

For a class, Thread save" is not that easily defined.

e.g.:

It can be fully thread save (like TThreadList): you can call any function/property at any time from any thread.
It could be allowed to create multiple instances in multiple threads and use each of them with it's own thread but not with others (holds for TList) It could be allowed to crate an instance with one thread and after that use functions/properties with a single other one. (e.g.: TList) it could be allowed to use all instances of the class only in a one and only thread.
It could be allowed to be used only in a predefined (e.g. the main-) thread (many classes in the LCL).
...

-Michael

Xiangrong Fang
to Michael Van Canneyt: TFPList is not thread-safe. You need to use TThreadList if you want a thread-safe list.…

2014-10-02 14:16 GMT+08:00 Michael Van Canneyt :

Show quoted text 5 lines
TFPList is not thread-safe. You need to use TThreadList if you want a thread-safe list. Critical sections use OS calls, so there is always a performance penalty.

I think the only thread-critical operation I need is to add item to the list, so I will use critical section myself, not replace TFPList with TThreadList, for simplicity and performance reason...

Xiangrong

Michael Schnell
to Michael Van Canneyt: TFPList is not thread-safe. You need to use TThreadList if you want a thread-safe list.…
Michael Van Canneyt wrote
Critical sections use OS calls, so there is always a performance penalty.

That is what Futex is made for.

AFAIR, in Linux, the fpc RTL calls the pthread library "mutex..." function. This library uses Futex, if the arch supports that, and uses the plain old MUTEX system call if the arch does not support FUTEX.

("FUTEX" = " Fast Userland MutEX" only does an OS call when necessary (i.e. when a thread needs to wait or when another thread needs to be woke). So in by fat most instances it just does a (atomic) userland operation.)

-Michael

Xiangrong Fang
to Michael Schnell

2014-10-02 22:09 GMT+08:00 Michael Schnell :

Show quoted text 5 lines
AFAIR, in Linux, the fpc RTL calls the pthread library "mutex..." function. This library uses Futex, if the arch supports that, and uses the plain old MUTEX system call if the arch does not support FUTEX.

I need my program to work on both Linux and Windows, can I still use FUTEX? For Critical Sections, FPC has the TCriticalSection object, is there a TMutex object?

Xiangrong

Xiangrong Fang
to Xiangrong Fang

2014-10-02 22:23 GMT+08:00 Xiangrong Fang :

Show quoted text 9 lines
2014-10-02 22:09 GMT+08:00 Michael Schnell : > > AFAIR, in Linux, the fpc RTL calls the pthread library "mutex..." > function. This library uses Futex, if the arch supports that, and uses the > plain old MUTEX system call if the arch does not support FUTEX.

I found some quotes online:

For Windows, critical sections are lighter-weight than mutexes.

Mutexes can be shared between processes, but always result in a system call to the kernel which has some overhead. Critical sections can only be used within one process, but have the advantage that they only switch to kernel mode in the case of contention.

I only need lock WITHIN my own application, so, it seems that critical sections are better.

Xiangrong

Jonas Maebe
to Xiangrong Fang: 2014-10-02 14:16 GMT+08:00 Michael Van Canneyt : I think the only thread-critical…
Xiangrong Fang wrote
I think the only thread-critical operation I need is to add item to the list, so I will use critical section myself, not replace TFPList with TThreadList, for simplicity and performance reason...

It will make your program unstable (adding an element to an fplist can cause the entire internal array to move, so if you are in the middle of a read operation at the same time, that read operation will either read invalid data or crash). Unless you are an expert at multithreaded programming, don't try to optimise existing thread-safe structures (and definitely don't perform premature optimisations).

Jonas

Xiangrong Fang
to Jonas Maebe

2014-10-02 23:07 GMT+08:00 Jonas Maebe :

Show quoted text 11 lines
On 02 Oct 2014, at 15:59, Xiangrong Fang wrote: It will make your program unstable (adding an element to an fplist can cause the entire internal array to move, so if you are in the middle of a read operation at the same time, that read operation will either read invalid data or crash). Unless you are an expert at multithreaded programming, don't try to optimise existing thread-safe structures (and definitely don't perform premature optimisations). I don't intend to do any optimization. I just think that I need to enter a

critical section, add item to the list, then leave the critical section.

I am definitely not expert in thread programming, but I am clear about the logic of my class and program. Actually, it is a TTree object I wrote, using TFPList to store sibling nodes. There are a lot of TFPList (one per tree node). I just need to make sure that there are no more than one thread operating on the same node at the same time.

Xiangrong

José Mejuto
to Xiangrong Fang
Xiangrong Fang wrote
I don't intend to do any optimization. I just think that I need to enter a critical section, add item to the list, then leave the critical section.

Hello,

You must protect with a CriticalSection, "Add" and any other kind of access, like indexed access. As you must protect indexed access you are in the same penalty as using TThreadList.

Threading example to a crash (numbers are execution steps):

Thread 1
--------
1-Resolve TList data access to $00010000
2-calculate item 23 is at $00010023
3-Read $00010023
4-Crash or read from unalocated memory (content undefined).

Thread 2
--------
1-Enter "Add" function and resolve Tlist data to $00010000 2-Lock thread and find that it need to relocate data to $00020000. Move data 3-Unlock
4-Continue

Michael Schnell
to Xiangrong Fang: 2014-10-02 22:09 GMT+08:00 Michael Schnell : I need my program to work on both Linux and…
Xiangrong Fang wrote 5 lines
I need my program to work on both Linux and Windows, can I still use FUTEX?

I did not recommend to use FUTEX yourself. Futex is a rather complicated thingy that needs ASM for a combination of atomic user land operations and system calls (that are done if necessary).

In Linux, the userland Futex stuff is done for you (if possible at all) in the ppthead library mutex_...() functions.

I am not sure that the fpc RTL in fact uses the pthread (standard C-language) library for TCrtitical section, but this would make sense, as in that library the dirty stuff is handled. (E.g. _not_ using FUTEX, but plain old MUTEX in case the arch does not provide FUTEX - there are several archs that don't provide FUTEX - AFAIK, X86, X86/64 and ARM32 do provide it).

Regarding Windows, I have not much knowledge about such low-level stuff. AFAIK, all Windows system calls are done via DLLs, and so always some Microsoft code is executed in Userland, anyway. Hence it is well possible that the Window "MUTEX" System-DLL-Call (like the pthreadlib so in Linux) automatically does a FUTEX-alike thingy.

For Critical Sections, FPC has the TCriticalSection object, is there a TMutex object?

AFAI understand, "CriticalSection" is the Delphi/fpc name for "POSIX-Mutex".

Of course you can do you own low-level implementation of a MUTEX/FUTEX Sync-Object. Doing that directly in ASM might be slightly faster than calling the C-phtreadlib. But this definitively is hard stuff. (Unfortunately Linux does not - and supposedly will not very soon support the rather new "vdso" concept - a kind of user-land system calls
- for FUTEX/MUTEX).

-Michael

Michael Schnell
to Xiangrong Fang: 2014-10-02 22:23 GMT+08:00 Xiangrong Fang : I found some quotes online: For Windows,…
Xiangrong Fang wrote 14 lines
For Windows, critical sections are lighter-weight than mutexes. Mutexes can be shared between processes, but always result in a system call to the kernel which has some overhead. Critical sections can only be used within one process, but have the advantage that they only switch to kernel mode in the case of contention. I only need lock WITHIN my own application, so, it seems that critical sections are better.

So it seems that Windows in fact does a kind of FUTEX for inter-Thread synchronizing (as does pthredlib, that as it's name says just provides POSIX-operation within Threads, not between applications.)

Hence, provided TCrtiticalSections uses the Windows system DLL in Windows and the pthreadlib so in Linux, the resulting performance should be very similar.

-Michael

Marco van de Voort
to Michael Schnell: I did not recommend to use FUTEX yourself. Futex is a rather complicated thingy that…

In our previous episode, Michael Schnell said:

Show quoted text 5 lines
> For Critical Sections, FPC has the TCriticalSection object, is there a > TMutex object? AFAI understand, "CriticalSection" is the Delphi/fpc name for "POSIX-Mutex".

Critical sections are bound to the owning process under Windows, while Windows mutexes can span processes (and thus are more expensive).

So critical section is equal to posix mutex with PTHREAD_PROCESS_PRIVATE attribute.

Michael Schnell
to Marco van de Voort
Marco van de Voort wrote
So critical section is equal to posix mutex with PTHREAD_PROCESS_PRIVATE attribute.

Thanks for the clearness !

(The OP of course just wants just this - synchronization between threads of a single application.)

-Michael

Marco van de Voort
to Michael Schnell

In our previous episode, Michael Schnell said:

Show quoted text 6 lines
> So critical section is equal to posix mutex with > PTHREAD_PROCESS_PRIVATE attribute. Thanks for the clearness ! (The OP of course just wants just this - synchronization between threads of a single application.)

On *nix for critical section, cthreads creates a mutex of the recursive type(_PTHREAD_MUTEX_RECURSIVE) but doesn't set that attribute, but it seems(*) that the above attribute(PTHREAD_PROCESS_PRIVATE) is default.

(*) http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_mutexattr_getpshared.html
Dennis Poon
to Michael Schnell: I don't suppose it will be possible to beat TThreadList performance by any home-brew…
Michael Schnell wrote 6 lines
On 10/02/2014 03:59 PM, Xiangrong Fang wrote: > , not replace TFPList with TThreadList, for simplicity and > performance reason... I don't suppose it will be possible to beat TThreadList performance by any home-brew Pascal code, which is same is not insecure.

But I looked at the source code of TThreadList,

procedure TThreadList.Add(Item: Pointer);
   begin
     LockList;
     try
       if (Duplicates=dupAccept) or
         // make sure it's not already in the list
         (FList.IndexOf(Item)=-1) then
          FList.Add(Item)
        else if (Duplicates=dupError) then
          FList.Error(SDuplicateItem,PtrUInt(Item));
     finally
       UnlockList;
     end;
   end;

where

function TThreadList.LockList: TList;
   begin
     Result:=FList;
     System.EnterCriticalSection(FLock);
   end;

There is no special simply calls
System.EnterCriticalSection(FLock),
so performance should be JUST THE SAME as wrapping a pair of critical section enter/leave around the code ourselves.

Dennis

Michael Schnell
to Dennis Poon
Dennis Poon wrote 8 lines
function TThreadList.LockList: TList; begin Result:=FList; System.EnterCriticalSection(FLock); end;

Yep.

System.EnterCriticalSection is a procedure variable that is set according to the OS and arch the project is compiled for.

In Linux without UseCThreads it is just an empty function. (OK here creating threads is not allowed)
In Linux with UseCThreads it is just an empty function it is a call to pthread_mutex_lock, which is in the pthreadlib so file and calls FUTEX or MUTEX, such as appropriate. (So don't try to "optimize" !!! ) In Windows I suppose it does a call to the Windows system DLL that supposedly does a FUTEX workalike. (So don't try to "optimize" !!! )

Show quoted text 5 lines
There is no special simply calls System.EnterCriticalSection(FLock), so performance should be JUST THE SAME as wrapping a pair of critical section enter/leave around the code ourselves.

Yep. (So don't try to "optimize" !!! )

-Michael