11

Delphi 10.2 (having support for Linux) has a cross Platform function AtomicExchange which is equivalent to Windows InterlocekdEchange. So far so good...

I have to port Win32 code making use of InterlockedExchangeAdd which has no AtomicExchangeAdd equivalent.

My question is: what can I use to replace InterlockedExchangeAdd when compiling for Linux ?

fpiette
  • 11,983
  • 1
  • 24
  • 46

2 Answers2

11

There is a hidden implementation of this function in System.SysUtils.pas:

function AtomicExchangeAdd(var Addend: Integer; Value: Integer): Integer;
begin
  Result := AtomicIncrement(Addend, Value) - Value;
end;

It makes use of the fact that AtomicIncrement returns the new value of Addend, while InterlockedExchangeAdd returns the old value. Subtracting Value gives the expected result and obviously is thread-safe.

Uwe Raabe
  • 45,288
  • 3
  • 82
  • 130
10

InterlockedExchangeAdd() "performs an atomic addition of Value to the value pointed to by Addend. The result is stored in the address specified by Addend."

The System.SyncObjs unit has a TInterlocked class, which has overloaded Add() methods to do the same thing:

Increments an integer value with another.

There are two overloaded Add methods. Both Add methods increment a Target by Increment.

class function Add(var Target: Integer; Increment: Integer): Integer; overload; static; inline;

class function Add(var Target: Int64; Increment: Int64): Int64; overload; static; inline;

The difference is that InterlockedExchangeAdd() "returns the initial value of the variable pointed to by Addend", whereas TInterlocked.Add() "returns the value of the incremented parameter" instead. So, if you use the return value, you will have to account for that difference, eg:

function InterlockedExchangeAdd(var Addend: Integer; Value: Integer): Integer;
begin
  Result := TInterlocked.Add(Addend, Value) - Value;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770