C++ / a working model

132 / 163   ·   C11   ·   8 min

Locks

Keep this sentence

Locks let programmers protect critical sections so that updates to shared data occur atomically, avoiding race conditions among concurrent threads.

In this lesson
  1. Protecting Shared Updates with Locks
  2. Fine-grained versus Coarse-grained Locking
  3. Hardware and OS Support for Lock Implementation
  4. Limitations of the Interrupt-Masking Approach
  5. Example
  6. Exercise

Official chapter PDF

Protecting Shared Updates with Locks

Programmers invoke lock acquire and release around sensitive code. This makes the enclosed operations appear atomic to other threads. The lock variable records whether it is free or held by a single thread.

Fine-grained versus Coarse-grained Locking

A single global lock forces every critical section to run serially. Independent locks for distinct data structures raise parallelism by allowing unrelated operations to proceed together.

Hardware and OS Support for Lock Implementation

Efficient locks rely on atomic read-modify-write instructions supplied by the processor together with operating-system facilities that put a thread to sleep instead of spinning while a lock is held.

Limitations of the Interrupt-Masking Approach

Turning interrupts off works solely on a uniprocessor and grants user programs too much privilege; a buggy or hostile program can render the system unresponsive to hardware events.

Pitfalls

  • Omitting the unlock call leaves waiting threads blocked forever.
  • Performing a potentially sleeping operation while a lock is held readily produces deadlock.

Run an example

Minimum C11 · complete program · Download .c

#include <stdio.h>
#include <pthread.h>

static int shared_counter = 0;
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

static void *worker(void *arg) { (void)arg;
    (void)arg;
    for (int i = 0; i < 5000; ++i) {
        pthread_mutex_lock(&mtx);
        ++shared_counter;
        pthread_mutex_unlock(&mtx);
    }
    return NULL;
}

int main(void) {
    pthread_t t1, t2;
    pthread_create(&t1, NULL, worker, NULL);
    pthread_create(&t2, NULL, worker, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    printf("Shared counter is %d\n", shared_counter);
    return 0;
}

Compile locally

gcc -std=c11 -Wall -Wextra -Wpedantic -Werror -pthread ostep-28-locks.c -o example && ./example

Expected result

Shared counter is 10000

CHECK YOUR UNDERSTANDING

Close the answer. Explain it.

Why can a lock built from an ordinary flag variable not guarantee mutual exclusion?

Show a reference answer

The test that the flag is free and the following store that marks it occupied can be interrupted, allowing several threads to enter the critical section at once.

Check the sources

Drafts and official chapters change. The version mark is only the example’s minimum.

Back to the catalog