Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing Atomic operation with non atomic operation

In the delphi source code we have :

class function TNetEncoding.GetBase64Encoding: TNetEncoding;
var
  LEncoding: TBase64Encoding;
begin
  if FBase64Encoding = nil then
  begin
    LEncoding := TBase64Encoding.Create;
    if AtomicCmpExchange(Pointer(FBase64Encoding), Pointer(LEncoding), nil) <> nil then
      LEncoding.Free
{$IFDEF AUTOREFCOUNT}
    else
      FBase64Encoding.__ObjAddRef
{$ENDIF AUTOREFCOUNT};
  end;
  Result := FBase64Encoding;
end;

but I don't understand, they mix Atomic operation (AtomicCmpExchange(Pointer(FBase64Encoding), Pointer(LEncoding), nil) with non atomic operation like if FBase64Encoding = nil then and Result := FBase64Encoding;

Is it not a mistake ?

like image 430
zeus Avatar asked Jan 09 '19 07:01

zeus


People also ask

What is non-atomic operation?

Non-Atomic CPU InstructionsA memory operation can be non-atomic even when performed by a single CPU instruction. For example, the ARMv7 instruction set includes the strd instruction, which stores the contents of two 32-bit source registers to a single 64-bit value in memory.

Why do we use atomic and non-atomic and what is default Behaviour?

Atomic:- is the default behavior. it will ensure the present process is completed by the CPU, before another process accesses the variable.it is not fast, as it ensures the process is completed entirelyNon-Atomic: - is NOT the default behavior.

Why do we need atomic operations?

During an atomic operation, a processor can read and write a location during the same data transmission. In this way, another input/output mechanism or processor cannot perform memory reading or writing tasks until the atomic operation has finished.

What is an atomic operation example?

An example of atomic operation is instruction execution, usually an instruction feed to the execution unit can't be stopped in the middle. Yet, a statement in high level language results in multiple instructions. It is the root cause of non-atomic operations.


1 Answers

In the comments you make it clear that your concern is that the unprotected memory operations could tear. By tearing we mean that a read thread reads the variable when it is partially written.

That is a valid concern in general, but tearing cannot happen in this case. The reason being is that aligned memory access is guaranteed not to tear. When the memory operation is aligned, as this one is, a reader cannot read a partially written variable. This is typically guaranteed by the hardware bus serializing all memory access within a single cache line.

So, no, this is not a mistake, the code is correct.

The code itself is used to lazily create a singleton. A common technique to do so in a threadsafe manner is double checked locking. This code uses an alternative technique that avoids locking. Instead, the code potentially allows multiple threads to speculatively create the singleton. If more than one thread succeeds in creating the object, the first one to succeed wins, and the other threads destroy their instances and use the one created by the winner thread.

The lock free approach works well provided that it is benign to create additional instances and then destroy them. But this will not always be the case. For example, it may be too expensive to create multiple copies of the instance. In such cases a lock based approach is better.

like image 103
David Heffernan Avatar answered Oct 10 '22 23:10

David Heffernan