tags:

views:

1319

answers:

4

Are 'boolean' variables thread-safe for reading and writing from any thread? I've seen some newsgroup references to say that they are. Are any other data types available? (Enumerated types, short ints perhaps?)

It would be nice to have a list of all data types that can be safely read from any thread and another list that can also be safely written to in any thread without having to resort to various synchronization methods.

+4  A: 

On 32-bit architecture, only properly aligned 32-bit or less data types should be considered atomic. 32-bit values must be 4-aligned (address of the data must be evenly divisible by four). You probably wouldn't run into interleaving at such tight level, but theoretically you could have double, Int64 or Extended non-atomic write.

eed3si9n
+5  A: 

This is not a question of data types being thread-safe, but it is a question of what you do with them. Without locking no operation is thread-safe that involves loading a value, then changing it, then writing it back: incrementing or decrementing a number, clearing or setting an element in a set - they are all not thread-safe.

There is a number of functions that allow for atomic operations: interlocked increment, interlocked decrement, and interlocked exchange. This is a common concept, nothing specific to Windows, x86 or Delphi. For Delphi you can use the InterlockedFoo() functions of the Windows API, there are several wrappers around those too. Or write your own. The functions operate on integers, so you can have atomic increment, decrement and exchange of integers (32 bit) with them.

You can also use assembler and prefix ops with the lock prefix.

For more information see also this StackOverflow question.

mghie
+3  A: 

Please note that you can make essentially everything in delphi unthreadsafe. While others mention alignment problems on boolean this in a way hides the real problem.

Yes, you can read a boolean in any thread and write to a boolean in any thread if it's correctly aligned. But reading from a boolean you change is not necessarily "thread safe" anyway. Say you have a boolean you set to true when you've updated a number so that another thread reads the number.

if NumberUpdated then
begin
  LocalNumber = TheNumber;
end;

Due to optimizations the processor makes TheNumber may be read before NumberUpdated is read, thus you may get the old value of TheNumber eventhough you updated NumberUpdated last.

Aka, your code may become:

temp = TheNumber;
if NumberUpdated the
begin
  LocalNumber = temp;
end;

Imho, a basic rule of thumb:
"Reads are thread safe. Writes are not thread safe."
So if you're going to do a write protect the data with synchronization everywhere you read the value while a write could potentially occur.
On the other hand, if you only read and write a value in one thread, then it's thread safe. So you can do a large chunk of writing in a temporary location, then synchronize an update of applicationwide data.

Bonus blurb:

The VCL is not thread safe. Keep all modification of ui stuff in the main thread. Keep the creation of all ui stuff in the main thread too.

Many functions are not thread safe either, while others are, it often depends on the underlying winapi calls.

I don't think a "list" would be helpful as "thread safe" can mean a lot of stuff.

PetriW
+1, very good points. For anybody interested, check out for example http://en.wikipedia.org/wiki/Memory_barrier and the linked information.
mghie
A: 

The Indy code contains some atomic / thread safe data types in IdThreadSafe.pas:

  • TIdThreadSafeInteger
  • TIdThreadSafeBoolean
  • TIdThreadSafeString
  • TIdThreadSafeStringList and some more ...
mjustin