Β§28.1–28.5Locks: The Basic Idea … Controlling Interrupts

Part II OSTEP pp. 315–318 Β· ~4 min read

  • lock
  • fine-grained locking

Chapter 26 posed the problem: sequences we wish were atomic, shredded by interrupts and parallelism. The direct attack is the lock .

28.1 Locks: The Basic Idea

The canonical critical section:

balance = balance + 1;

To protect it, bracket it:

lock_t mutex; // some globally-allocated lock 'mutex'
...
lock(&mutex);
balance = balance + 1;
unlock(&mutex);

A lock is just a variable, holding one of two states: available (unlocked, free) or acquired (locked, held) β€” held by exactly one thread, the owner, presumably inside the critical section. (The type may hide more β€” the holder’s identity, a queue of waiters β€” but that’s the implementation’s business.)

Semantics: lock() tries to acquire; if the lock is free, the caller takes it and enters. If another thread holds it, the call does not return while that remains true. unlock() frees it β€” and if threads are stuck waiting, one of them will (eventually) notice or be informed, acquire, and enter. The deeper point: threads are scheduled by the OS, chaotically; a lock hands a little of that control back β€” no more than one thread will ever be active in this code.

28.2 Pthread Locks

POSIX calls its lock a mutex (it provides mutual exclusion β€” one thread in, others excluded):

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

Pthread_mutex_lock(&lock); // wrapper; exits on failure
balance = balance + 1;
Pthread_mutex_unlock(&lock);

Note the lock is passed in: different locks can protect different data. One big lock for everything is coarse-grained; a lock per structure β€” fine-grained locking β€” lets more threads run locked code at once.

28.3 Building A Lock

You now know how a lock behaves. But how does one build it?

The Crux: How To Build A Lock

How can we build an efficient lock? Efficient locks provide mutual exclusion at low cost, and might attain a few other properties. What hardware support is needed? What OS support?

Answering takes both old friends: hardware (atomic instructions, arriving over the next sections) and the OS (sleeping support, arriving after that).

28.4 Evaluating Locks

First, the grading rubric:

How to grade a lock β€” the rubric every design in this chapter faces
the question
mutual exclusiondoes it WORK β€” does it keep multiple threads out of the critical section?
fairnessdoes every contender get a fair shot once the lock frees β€” or can a thread STARVE, never obtaining it?
performancewhat overhead does the lock add?
Dotted-underlined cells have explanations β€” click one.

28.5 Controlling Interrupts

The earliest solution, from the single-processor era:

void lock() {
    DisableInterrupts();
}
void unlock() {
    EnableInterrupts();
}

No interrupts, no interleaving β€” inside the section, your code runs as if atomic. One virtue, many vices:

Mutual exclusion by turning off interrupts: the scorecard
because…
βœ“ simplicityno interrupts β†’ no interleaving β†’ the section is effectively atomic
βœ— trustarbitrary programs get a privileged operation
βœ— multiprocessorsdisabling interrupts on one CPU stops nothing on the others
βœ— lost interruptsmask too long and events vanish
βœ— slowmask/unmask instructions execute slowly on modern CPUs
Dotted-underlined cells have explanations β€” click one.

Interrupt masking thus survives only in limited contexts: inside the OS itself, guarding kernel structures or avoiding messy interrupt-handling situations β€” where the trust issue disappears, since the OS always trusts itself with privileged operations anyhow. For everyone else, we need something better β€” and the hardware is about to provide it.

Check yourself

1.What states can a lock variable be in, and what do lock()/unlock() promise?

2.Why does the POSIX API pass a lock VARIABLE to lock/unlock rather than having one global lock?

3.Name the three axes for evaluating a lock β€” and the three performance cases worth separating.

4.lock() = DisableInterrupts() was the earliest mutual exclusion. List the fatal flaws.

5.Despite everything, interrupt masking still gets used. Where, and why is it OK there?

5 questions