Synchronization and Critical Sections
Overview
This week explores one of the most important challenges in multithreaded programming — synchronization.
Students will understand how race conditions arise when multiple threads access shared data concurrently, and how to control access to critical sections using synchronization primitives such as mutexes, spinlocks, semaphores, condition variables, and atomic operations.
Key Concepts
Concurrency and Race Conditions
- Race condition: when multiple threads access and modify shared data simultaneously, leading to unpredictable results.
- Critical section: a segment of code that must not be executed by more than one thread at a time.
- Data consistency: maintaining integrity of shared resources under concurrent access.
Synchronization Primitives
-
Mutex (Mutual Exclusion Lock):
- Ensures only one thread executes a critical section at a time.
- Core functions:
pthread_mutex_init,pthread_mutex_lock,pthread_mutex_unlock,pthread_mutex_destroy.
-
Spinlock:
- Lightweight lock that continuously checks availability without sleeping.
- Suitable for short critical sections on multicore systems.
-
Semaphore:
- A counter-based synchronization mechanism for controlling access to a finite number of resources.
- POSIX functions:
sem_init,sem_wait,sem_post,sem_destroy.
-
Condition Variable:
- Used for signaling between threads.
- Allows a thread to wait until a certain condition becomes true.
- Core functions:
pthread_cond_wait,pthread_cond_signal,pthread_cond_broadcast.
-
Atomic Operations and CAS (Compare-And-Swap):
- Low-level operations ensuring atomic updates without explicit locks.
- Foundation for lock-free synchronization structures.
Deadlocks and Starvation (Intro)
- Circular wait, hold and wait, no preemption, mutual exclusion — the four conditions for deadlock.
- Techniques to avoid or detect deadlocks will be discussed in future weeks.
Practice
Demonstrating Race Conditions
- Create a shared counter updated by multiple threads without locks — observe inconsistent results.
- Protect the counter using a mutex and verify correct output.
Working with Mutexes
- Use a mutex to protect a critical section in a multi-threaded program.
- Experiment with
pthread_mutex_trylockandPTHREAD_MUTEX_RECURSIVE.
Using Semaphores
- Implement a simple producer-consumer synchronization using semaphores.
Condition Variables
- Demonstrate thread signaling (one thread waits until another signals a condition).
- Compare busy-waiting vs. condition-based waiting.
Spinlocks and Atomics
- Experiment with short critical sections using spinlocks.
- Observe CPU utilization differences compared to mutexes.
Homework
References
Required
- ECE 252 Lecture 12: Concurrency: Synchronization & Atomicity
- ECE 252 Lecture 13: Semaphores
- ECE 252 Lecture 14: Synchronization Patterns
- Параллельное программирование. Лекция 2 Лекция
- Mutex vs Semaphore
- Spinlocks - Part 1 - A Basic Spinlock
- Compare-and-swap
- Advanced Programming in the UNIX Environment — W. Richard Stevens, Chapter 12 “Thread Synchronization”
- Programming with POSIX Threads — David R. Butenhof, Chapters 4–6
- Operating Systems: Three Easy Pieces — Chapters “Concurrency,” “Locks,” and “Condition Variables”
Recommended
- ECE 252 Lecture 16: The Readers-Writers Problem
- ECE 252 Lecture 17: Deadlock
- ECE 252 Lecture 18: Deadlock Avoidance
- ECE 252 Lecture 19: Deadlock Detection and Recovery
- Mutex lock for Linux Thread Synchronization
- How to use Semaphores in POSIX Concurrency Control
- Linux manual page - pthread_mutex_init(3p)
- Linux manual page - pthread_mutex_destroy(3p)
- Linux manual page - pthread_mutex_lock(3p)
- Linux manual page - pthread_mutex_unlock(3p)
- Linux manual page - spin_lock(3)
- Linux manual page - spin_unlock(3)
- Linux manual page - sem_init(3)
- Linux manual page - sem_destroy(3p)
- Linux manual page - sem_wait(3)
- Linux manual page - sem_post(3)
- Linux manual page - pthread_cond_wait(3)
- Linux manual page - pthread_cond_signal(3)
Quiz (Self-Check)
- What causes a race condition?
- What is the difference between a mutex and a spinlock?
- How does a semaphore differ from a mutex?
- What are the typical use cases for condition variables?
- What does “atomic operation” mean?
- Name the four necessary conditions for a deadlock.
- Why is it important to minimize the time spent inside a critical section?