Sign in Join

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

Mailing lists / fpc-devel / 2010-01

threadlocalvar unLOCKed variables

3 messages · 2 people ·

Reply by email Subscribe to this list Your subscription

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

A. Bouchez

I made a proposal in http://wiki.freepascal.org/Modernised_Pascal

20) threadlocalvar unLOCKed variables i.e. strings and dynamic arrays local to the current thread: reference-counted without the asm LOCK, "copy and write" only with other threadlocalvar, thread-local heap (without any asm LOCK either). It will increase the speed a lot in multi-core architectures, which don't like asm LOCK (freezes all cores for safe multi-thread). Note: this LOCK is implemented in the RTL in inclocked() and declocked() processor-specific functions.

function TServer.ComputePage: string;
threadlocalvar
  tmp: string; // differs from var tmp: string
  i: integer;  // i is defined as threadlocalvar, but is the same as normal var
begin
  for i := 0 to high(ListStr) do // ListStr[] is a dynamic array
    tmp := tmp+ListStr[i]+#13#10; // very fast computation, without LOCK
  result := tmp; // copy from local heap to global heap
end;

To implement this at the compiler and RTL level, we could use reference count < -2 for these variables (-1=const, -2=ref 0, -3=ref 1..). For example:

Procedure fpc_AnsiStr_Incr_Ref (S : Pointer); [Public,Alias:'FPC_ANSISTR_INCR_REF'];  compilerproc; {$IFNDEF VER2_0} Inline; {$ENDIF}
Begin
  If SNil then
    If PAnsiRec(S-FirstOff)^.Ref<0 then begin
      If PAnsiRec(S-FirstOff)^.Ref<-1 then  // -1 for const
        dec(PAnsiRec(S-FirstOff)^.Ref); // threadlocalvar fast reference count
    end else
      inclocked(PAnsiRec(S-FirstOff)^.Ref); // threadsafe reference count
end;

And a local threadheap should be implemented for such threadlocalvar, with threadlocalgetmem() and such functions.

Another possibility should be do add a "threadlocal" attribute for types, to be used for local variables and properties:

TServer = class
public
  ListStr: threadlocal array of string;
 ...

In this case, the method above should begin with:

function TServer.ComputePage: string;
var
  tmp: threadlocal string; // differs from var tmp: string
....

But this syntax sound a bit not "pascalish", whereas the threadlocalvar does (it sounds like the treadvar feature) ... another idea?

Reply by email

A. Bouchez

After looking forward in the heap.inc source file supplied with the 2.4.0 software release, I've some remarks:

It seems that small blocks of memory are allocated by thread, using the threadvar freelists declaration... Well..
1. How does it work on multi-thread? E.g. if you allocate a memory block in a thread, and that TWO threads call Reallocmem() at the same time?
2. If I understood well the new heap.inc threading mechanism, the threadlocalgetmem() and such functions I told about is pointless...

Great work done in coding the heap.inc file, indeed... and most classes are created much faster whith this new heap manager.

Another possibility of avoiding asm LOCK, should be to define some new string type (e.g. threadstring), which could also be more aware of string concatenation (allocate more memory at first to avoid most move during realloc). But the dynamic arrays would still use the LOCK.

Reply by email

Jonas Maebe
to A. Bouchez
A. Bouchez wrote
1. How does it work on multi-thread? E.g. if you allocate a memory block in a thread, and that TWO threads call Reallocmem() at the same time?

In the past that would have worked if both threads tried to reallocmem it to the same size (otherwise, depending on who got scheduled first, the final size could be too small), so there was only a synchronisation race. Now the result is probably unpredictable in all cases, so there is a data race.

I think in both cases the error is in the program though: you are using a pointer in two threads at the same time, with at least one thread modifying it. Even if both individual operations are atomic respective to each other (like with the old memory manager), depending on the order in which they execute you can still get different results.

Jonas

Reply by email