Spinlocks

A spinlock is a mechanism to allow only a single thread own thespinlock. A spinlock can be used between processes if the spinlock variable existsin shared memory. Spinlock's do not use the processor very efficiently since theycontinuously execute code until spinlock is owned. Therefore they should only beused when the expected wait/lock time is short. Spinlock's do have the advantagethat they do not cause a transfer to the operating system, which can be slow, andthey do not allocate any operating system resources.

While you can use a spinlock on a single processor machine thespinlock should not spin since this is a total waste of processor time. If the lockcannot be obtained then the thread should yield its processor time.

You can create your own spinlock by using the compiler intrinsicprocedures ATOMIC_CMPXCHG, ATOMIC_XCHG and MEMORY_FENCE.

A spinlock variable is initialized with a value of zero. A valueof zero means that no thread owns the spinlock. A value of one, or any non zero value,means that a thread owns the spinlock. Exactly which thread owns the spinlock isunknown.

To gain ownership of a spinlock

LOOP

    IF ATOMIC_XCHG(SpinLock, 1) = 0 THEN

        EXIT;

    END;

END;

MEMORY_FENCE;

This loop executes until the previous value in the spinlock variablewas zero. This means that nothing owned the spinlock before we put a value of 1 intothe spin lock, which marks it as owned. If the spinlock is already owned placinga one in the spinlock is harmless since a value of 1 was already in the spinlock.

LOOP

    IF ATOMIC_CMPXCHG(SpinLock, 0, 1) = 0 THEN

        EXIT;

    END;

END;

MEMORY_FENCE;

This is a much more efficient loop than the previous becausenothing is written to memory unless the previous value is zero, and only then a valueof one is written to the spinlock. The straight exchange always writes to memoryon each iteration of the loop, which causes senseless writes to memory which canhurt multiple CPU machine performance. This function also has another benefit inthat you can use multiple unique values to indicate that a spinlock is owned. Forexample, this value could indicate what thread actually owns the spinlock. This worksbecause the value you are assigning is not actually assigned to the spinlock variableunless the variable contains the value indicating lack of ownership. In this example0 indicates no ownership.

One final potential improvement to the spinlock.

LOOP

    IF SpinLock = 0 THEN

        IF ATOMIC_CMPXCHG(SpinLock, 0, 1)= 0 THEN

            MEMORY_FENCE;

            EXIT;
       END;
   END;

END

This spinlock modification spins on a simple read and not a buslocked operation. This may provide better performance on some multi-processor computers.

To release a spinlock

MEMORY_FENCE;

Lock := 0;

You place the memory fence before the release of the spinlockto ensure that all memory writes are visible to other processors before you releasethe lock.

Spinlock Variations

Here is a spinlock that gives up its time slice if it cannotown the spinlock. This makes the spinlock a bit less "wasteful" of totalprocessor time.

LOOP

    IF ATOMIC_CMPXCHG(SpinLock, 0, 1) = 0 THEN

        EXIT;

    END;

    SleepThread(0);

END;

MEMORY_FENCE;

Here is a spinlock with a spin count.

spin := spinCount;

LOOP

    IF ATOMIC_CMPXCHG(SpinLock, 0, 1) = 0 THEN

        EXIT;

    ELSIF spin <> 0 THEN

        spin := spin - 1;

    ELSE

        SleepThread(0);

        spin := spinCount;

    END;

END;

MEMORY_FENCE;

Spinning only makes sense on multiple processor machines. Givingup your time slice causes a task switch, which is "slow", and hence youonly do that periodically. The optimum value for spinCount is zero for single CPUmachines and must be determined empirically for multiple CPU machines.