Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Are strings and dynamic arrays thread-safe for read-only access in D7?

838 views
Skip to first unread message

Magnus Oskarsson

unread,
Nov 12, 2003, 12:52:07 PM11/12/03
to
I have read long newsgroup discussions about the introduction of thread-safe
reference counting for strings and dynamic arrays with Delphi 5. Have
Borland kept this for the later Delphi versions? The reason I am asking is
because I have seen some occasional strange behaviour in some D7
multi-threaded apps that could be explained if the reference counting were
_not_ thread safe. What we do in those apps is basically the following:
1. Thread A dynamically allocates a record which it fills with information
of interest to thread B. The record has besides simple types a string and a
dynamic array (hell, lets throw in a Variant as well, we had that in one
case).
2. The record pointer is passed by A to a common data structure (protected
by a critical section). From this point A either (I) never uses the record
pointer again, or (II) waits for a signal from B that B is finished using
it.
3. Thread B checks the common data structure in its main loop (again
protected by CS) and picks up the record pointer. Then it performs some
action based on the information. In case II it might update some of the data
in the record (only the simple fields however).
4. Thread B disposes the record (I), or B signals A that it is finished
(II), so that A can dispose the record (possible after reading some of the
simple type record fields).
Note: TThread descendants are used, so heap memory managment should be
thread-safe.

If the record contained only simple types (like integers) this should
(unless I have missed something major) be fool-proof (provided the actions
taken by B are safe of course), since the data that goes out of scope when A
and B continues processing is in no way shared. But with the dynamically
allocated types, the reference counts are shared, and things will happen
behind the scenes when data goes out of scope. I thought that these
behind-the-scenes things were thread safe, but as mentioned we have seen
some problems. Case I (which is the most common) has appeared to work well
from a functionality point of view, but we have observed memory leakage, and
the only indications from the testing software (AQTime) pointed at this
record handling (occasional memory leaks originating from New, NewAnsString
and ReallocateMem (the dynamic array I think) in System.pas). Case II gave a
nasty error the next time you accessed a seamingly totally unrelated object
(through an Interface), and this error disappeared if A did not dispose the
record in 4 but instead "recycled" it for use the next time. Can anyone shed
some light on this?

Regards

Magnus Oskarsson

Marc Rohloff

unread,
Nov 12, 2003, 2:00:41 PM11/12/03
to
On Wed, 12 Nov 2003 18:52:07 +0100, Magnus
Oskarsson<magnus.o...@enera.se> said ...

> I have read long newsgroup discussions about the introduction of thread-safe
> reference counting for strings and dynamic arrays with Delphi 5. Have
> Borland kept this for the later Delphi versions? The reason I am asking is
> because I have seen some occasional strange behaviour in some D7
Yes strings are thread safe. How do you allocate and dispose of your
records (Which functions) ?

Marc

Magnus Oskarsson

unread,
Nov 13, 2003, 2:19:23 AM11/13/03
to
> Yes strings are thread safe. How do you allocate and dispose of your
> records (Which functions) ?
>
> Marc

New/Dispose (on pointer variables of the appropriate type, e.g. PMyRec =
^TMyRec).

Magnus


madshi

unread,
Nov 13, 2003, 2:51:32 AM11/13/03
to
String assignments are thread safe, but only if you either use TThread
or if you manually set the variable "IsMultiThread := true".

However, if you have a loop like:

for i := 1 to length(strVar) do
strVar[i1] := '1';

while another thread does this:

strVar := '';

Then you have a problem. In that case you should synchronize access to
the string variable by using e.g. a critical section.

--
www.madshi.net
quality low level Delphi components
extended exception handling
API hooking, DLL injection
undocumented functionality

Craig Stuntz [TeamB]

unread,
Nov 13, 2003, 8:15:47 AM11/13/03
to
madshi (Mathias Rauen) wrote:

> String assignments are thread safe

Reading a string is thread safe; assigning to one requires
synchronization. I think this is what you meant, but it's not how your
syntax comes across here.

-Craig

--
Craig Stuntz [TeamB] . Vertex Systems Corp. . Columbus, OH
Delphi/InterBase Weblog : http://delphi.weblogs.com
InterBase PLANalyzer 1.1 -- Free InterBase query optimization
tool: http://delphi.weblogs.com/IBPLANalyzer

madshi

unread,
Nov 13, 2003, 1:47:31 PM11/13/03
to
> Reading a string is thread safe; assigning to one requires
> synchronization. I think this is what you meant

Actually that was not what I meant.

Are you sure that assigning requires synchronization? How do you define
"require"? Does assigning to an integer variable require
synchronization? As far as I can see, Delphi string variables seem to be
as thread safe as e.g. integer variables - apart from the length related
problems I talked about in my previous comment.

Please try the following code. It doesn't crash, nor do you get any
memory leaks:

var strVar : string;
stop : boolean = false;

function AssignStr(dummy: integer) : integer; stdcall;
begin
while not stop do
strVar := IntToHex(GetTickCount, 1);
result := 0;
end;

var tid, th1, th2 : dword;
mem : integer;
initialization
IsMultiThread := true;
mem := AllocMemSize;
th1 := CreateThread(nil, 0, @AssignStr, nil, 0, tid);
th2 := CreateThread(nil, 0, @AssignStr, nil, 0, tid);
MessageBox(0, 'test', 'test', 0);
stop := true;
WaitForSingleObject(th1, INFINITE);
WaitForSingleObject(th2, INFINITE);
CloseHandle(th1);
CloseHandle(th2);
strVar := '';
mem := AllocMemSize - mem;
MessageBox(0, pchar('mem leak: ' + IntToStr(mem)), 'info', 0);

Craig Stuntz [TeamB]

unread,
Nov 13, 2003, 1:04:45 PM11/13/03
to
madshi (Mathias Rauen) wrote:

> Are you sure that assigning requires synchronization? How do you
> define "require"? Does assigning to an integer variable require
> synchronization?

It's hardware dependent. AFAIK, it is safe on Intel CPUs in most
conditions, but I wouldn't want to make that presumption unless I was
confident I knew exactly which CPUs someone running my app would be
using and had checked the developer documentation for each of them.

> As far as I can see, Delphi string variables seem to
> be as thread safe as e.g. integer variables - apart from the length
> related problems I talked about in my previous comment.

I agree there's little difference between assigning to a string
variable and any other reference counted pointer, and that the refrence
counting issues were addressed in, what was it, D5?

Craig Stuntz [TeamB]

unread,
Nov 14, 2003, 11:31:49 AM11/14/03
to
madshi (Mathias Rauen) wrote:

> Are you sure about that it's hardware dependent?

Reading and writing a particular value is thread safe as long as the
read/write is an atomic operation on the CPU. This varies with CPU and
data type. Also, some operations are effectively atomic on a single
processor system but are not truly atomic on a SMP system.

AFAIK, a 32 bit integer read/write will always be atomic, but this is
an implementation detail of current processors, rather than a rule or
policy.

> There are
> only few asm instructions on Intel CPUs which are not
> supported by AMD, and IIRC none of them has to do with
> thread switching or synchronization.

Right, it doesn't have anything to do with *which* instructions are
supported, just how they're implemented.

-Craig

--
Craig Stuntz [TeamB] . Vertex Systems Corp. . Columbus, OH
Delphi/InterBase Weblog : http://delphi.weblogs.com

InterBase Performance Monitor -- Analyze and control your IB7
server: http://delphi.weblogs.com/IBPerformanceMonitor

madshi

unread,
Nov 14, 2003, 12:24:24 PM11/14/03
to
> It's hardware dependent. AFAIK, it is safe on Intel CPUs
> in most conditions

Are you sure about that it's hardware dependent? There are


only few asm instructions on Intel CPUs which are not
supported by AMD, and IIRC none of them has to do with
thread switching or synchronization.

> I agree there's little difference between assigning to a


> string variable and any other reference counted pointer,
> and that the refrence counting issues were addressed in,
> what was it, D5?

Yeah, I think it was D5.

madshi

unread,
Nov 15, 2003, 5:59:37 AM11/15/03
to
> Reading and writing a particular value is thread safe as long
> as the read/write is an atomic operation on the CPU. This
> varies with CPU and data type. Also, some operations are
> effectively atomic on a single processor system but are not
> truly atomic on a SMP system.

Well, we have the "lock" prefix to make some specific asm
instructions multi CPU safe.

> Right, it doesn't have anything to do with *which* instructions
> are supported, just how they're implemented.

Hmmm... Do you have a link about that? I mean I really doubt that there
are significant differences to which instructions are atomic or not
between Intel and AMD CPUs. IIRC, the Intel instruction reference it
pretty clear on what is atomic and what not. AMD would be silly to not
follow this specification. AMD CPUs would not be 100% x86 compatible in
that case.

Craig Stuntz [TeamB]

unread,
Nov 17, 2003, 9:42:19 AM11/17/03
to
madshi (Mathias Rauen) wrote:

> Well, we have the "lock" prefix to make some specific asm
> instructions multi CPU safe.

Yes, but I thought we were discussing stuff outside of an explicit
lock. Obviously, anything you lock is safe.

> > Right, it doesn't have anything to do with which instructions


> > are supported, just how they're implemented.
>
> Hmmm... Do you have a link about that? I mean I really doubt that
> there are significant differences to which instructions are atomic or
> not between Intel and AMD CPUs. IIRC, the Intel instruction reference
> it pretty clear on what is atomic and what not. AMD would be silly to
> not follow this specification. AMD CPUs would not be 100% x86
> compatible in that case.

Maybe I wasn't clear; I wasn't saying that AMD was different (you
brought up AMD, not me!). Only that Intel is free to change which reads
and writes are atomic in any CPU they introduce, and nobody can really
complain if they do. You have to presume that anything which happens
to be thread-safe outside the context of an explicit lock is an
implementation detail.

0 new messages