Home Thread safety read InterlockedIncremented value
Reply: 2

Thread safety read InterlockedIncremented value

zed
1#
zed Published in 2018-02-12 12:04:45Z

In my application several threads increment some counter and only one reads this value (main thread). As far I know, reading 32-bit value is thread-safe if it is aligned by double word, so I use such code:

{$A8}
TMyStat = class
private
  FCounter: Integer;
public
  procedure IncCounter;
  property Counter: Integer read FCounter;
...

procedure TMyStat.IncCounter;
begin
  InterlockedIncrement(FCounter);
end;

But I'm not sure that it's safe to mix Interlocked functions and direct access to value.

Should I use InterlockedCompareExchange instead?

function TMyStat.GetCounter: Integer;
begin
  Result := InterlockedCompareExchange(FCounter, 0, 0);
end;
gabr
2#
gabr Reply to 2018-02-12 12:40:41Z

You can use a normal read. As FCounter is 4-aligned, reading and writing is guaranteed to be atomic.

[This holds for Intel platforms, though. I really don't know how ARM behaves. I would guess that the behaviour is the same (reading of aligned value is atomic).]

Actually, if you only increment a counter and read it, you don't even need InterlockedIncrement. When you read the value you'll always get either the pre-increment or post-increment value. There's no way you get a mix of both.

Ian Boyd
3#
Ian Boyd Reply to 2018-02-13 14:53:51Z

Reading an aligned 32-bit value is atomic (i.e. all 32 bits are guaranteed to be consistent). But the read is not synchronized. You may not read the "current" value; but instead a value from the caches.

For example:

FCounter := 1; //number of threads running
FResult  := 0; //the answer to everything

And then your thread:

procedure ThreadProc;
begin
   FResult := 42; //set the answer before we indicate we're done
   InterlockedDecrement(FCounter);
end;

And then your code checks that the thread is done:

if (FCounter <= 0) then
begin
   //Thread is done; read the answer
   ShowMessage('The answer is: '+IntToStr(FResult));
   Exit;
end;

The answer is: 0

Even though your flag said the thread set the result, you read the result value out of your local cache.

  • Even though the read of FCounter and FResult is atomic
  • they aren't synchronized

If you are only using FCounter then you are fine. But as soon as you use anything else and expect them to be consistent, then you need to also use something to enforce synchronization.


The strict answer to your question is that reading a 32-bit aligned value is already an atomic operation.

But it's entirely possible that people coming here to read this question might forget that the read being atomic is a small part of your worries.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.298474 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO