Who Writes Turn

A ticket lock. Note that ticket is bumped with an atomic fetch-and-add but turn is bumped with a plain non-atomic read-modify-write:

typedef struct { int ticket; int turn; } lock_t;

void lock(lock_t *lk) {
    int myturn = FetchAndAdd(&lk->ticket);   // atomic
    while (lk->turn != myturn)
        ;                                    // spin
}

void unlock(lock_t *lk) {
    lk->turn = lk->turn + 1;                 // plain increment
}

Sixteen threads hammer this lock. Why does the plain increment in unlock never lose an update?

A

The FetchAndAdd on ticket emits a barrier that makes the later write to turn atomic as well.

B

Only the thread currently holding the lock ever executes unlock, so turn has exactly one writer at a time; every other thread only reads it while spinning.

C

An int increment compiles to a single instruction on x86, so it is atomic.

D

turn only ever increases, so even a lost update would leave the lock in a usable state.