In multi-threaded programming, we can find different terms for synchronizing data transfer between two or more threads / tasks.
When can we say that some kind of algorithm:
1)Lock-Free 2)Wait-Free 3)Wait-Freedom
I understand what Lock-free means, but when can we say that some sort of Wait-Free or Wait-Freedom synchronization algorithm? I made a code (ring buffer) for multi-threaded synchronization and uses Lock-Free methods, but:
- The algorithm predicts the maximum execution time for this procedure.
- Thread, which calls this procedure at the start, sets up a unique link (inside this procedure).
- Other threads that call the same procedure check this link, and if it is installed, then count the number of CPU samples (measurement time) of the first thread involved. If this time, you need to interrupt the current operation of the involved thread for a long time and cancels its operation.
- A topic that did not finish the task because it was interrupted from the task scheduler (fit) at the end of the link check, if it does not belong to him, repeat the task again.
Thus, this algorithm is actually not free from blocking, but memory locks are not used, and other involved threads may wait (or not) a certain time before overriding the task of the associated thread.
Added RingBuffer.InsertLeft function:
function TgjRingBuffer.InsertLeft(const link: pointer): integer; var AtStartReference: cardinal; CPUTimeStamp : int64; CurrentLeft : pointer; CurrentReference: cardinal; NewLeft : PReferencedPtr; Reference : cardinal; label TryAgain; begin Reference := GetThreadId + 1; //Reference.bit0 := 1 with rbRingBuffer^ do begin TryAgain: //Set Left.Reference with respect to all other cores :) CPUTimeStamp := GetCPUTimeStamp + LoopTicks; AtStartReference := Left.Reference OR 1; //Reference.bit0 := 1 repeat CurrentReference := Left.Reference; until (CurrentReference AND 1 = 0)or (GetCPUTimeStamp - CPUTimeStamp > 0); //No threads present in ring buffer or current thread timeout if ((CurrentReference AND 1 <> 0) and (AtStartReference <> CurrentReference)) or not CAS32(CurrentReference, Reference, Left.Reference) then goto TryAgain; //Calculate RingBuffer NewLeft address CurrentLeft := Left.Link; NewLeft := pointer(cardinal(CurrentLeft) - SizeOf(TReferencedPtr)); if cardinal(NewLeft) < cardinal(@Buffer) then NewLeft := EndBuffer; //Calcolate distance result := integer(Right.Link) - Integer(NewLeft); //Check buffer full if result = 0 then //Clear Reference if task still own reference if CAS32(Reference, 0, Left.Reference) then Exit else goto TryAgain; //Set NewLeft.Reference NewLeft^.Reference := Reference; SFence; //Try to set link and try to exchange NewLeft and clear Reference if task own reference if (Reference <> Left.Reference) or not CAS64(NewLeft^.Link, Reference, link, Reference, NewLeft^) or not CAS64(CurrentLeft, Reference, NewLeft, 0, Left) then goto TryAgain; //Calcolate result if result < 0 then result := Length - integer(cardinal(not Result) div SizeOf(TReferencedPtr)) else result := cardinal(result) div SizeOf(TReferencedPtr); end; //with end; { TgjRingBuffer.InsertLeft }
Here you can find RingBuffer : RingBuffer , CAS functions: FockFreePrimitives and test program: RingBufferFlowTest
source share