π₯ Letβs turn this into an elite-level Obsidian note for [[asymmetric_pthreads/07_shared_counter_with_mutex]]
β itβs one of the most fundamental building blocks for understanding threading, atomicity, and mutex behavior. π¦βοΈ
π§΅ 07_shared_counter_with_mutex
π Goal: Increment a global
counter
from 32 threads, each doing 100,000 iterations, while ensuring no race conditions occur via apthread_mutex_t
lock.
π§ The Code
#define THREAD_COUNT 32
#define ITERATIONS 100000
int counter = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-
π Each of the 32 threads calls
increment()
100,000 times. -
π A single global mutex ensures that only one thread at a time updates
counter
.
π increment()
Function
void *increment(void *arg)
{
int i = 0;
while (i < ITERATIONS)
{
pthread_mutex_lock(&lock);
counter += 1;
pthread_mutex_unlock(&lock);
i++;
}
return (NULL);
}
-
π§ Critical section:
pthread_mutex_lock(&lock); counter += 1; pthread_mutex_unlock(&lock);
-
This protects the read-modify-write sequence from race conditions.
π§ͺ Output Validation
printf("Final counter value: %d (Expected %d)\n", counter, THREAD_COUNT * ITERATIONS);
Expected: 32 * 100000 = 3,200,000
If you get any lower number, it means:
-
β You removed the mutex
-
π₯ There was a race condition corrupting
counter
π§ Why This Matters
title: Key Concepts Reinforced
collapse: open
- π§΅ **Thread interleaving**: without a mutex, many threads can read the same value and overwrite each other
- π **Mutex protects atomicity**: guarantees only one thread accesses `counter` at a time
- π― **Determinism**: using a mutex leads to predictable, correct output across all runs
β οΈ What If You Remove the Mutex?
// pthread_mutex_lock(&lock);
// counter += 1;
// pthread_mutex_unlock(&lock);
Final counter value: 2829471 (Expected 3200000)
Final counter value: 2198452 (Expected 3200000)
π₯ This is a classic data race. Some increments are lost due to concurrent access.
π§΅ Why Not Use ++counter
?
Because even counter++
is not atomic β itβs:
int tmp = counter;
tmp = tmp + 1;
counter = tmp;
Multiple threads can:
-
Read the same value
-
Write it back after incrementing
-
Overwrite each otherβs work
𧨠Boom: Race condition.
π§ What Can We Do Next?
title: Extensions & Experiments
- β
Replace `mutex` with `atomic_int` (see: [[08_atomic_counter_raceproof]])
- π Try increasing `THREAD_COUNT` to 512+ and benchmark latency
- π Time the execution with `clock_gettime` to see mutex cost
- β οΈ Comment out mutex to demonstrate live race conditions
- π₯ Add a sleep (`usleep(1)`) inside the loop to exaggerate contention
π Real World Analogy
This is like 32 people trying to update a shared spreadsheet π.
Without a lock on the spreadsheet, multiple people can erase each otherβs updates.
π Obsidian Links
- Follow-up: [[asymmetric_pthreads/08_atomic_counter_raceproof]]
- Related: [[asymmetric_pthreads/02_pthread_deadlock_simulation]]
- Related: [[asymmetric_pthreads/13_spinlock_and_compare_swap]]
β Summary
title: Recap
- π§΅ 32 threads each increment a shared counter
- π Mutex guarantees atomic updates
- β
Correct output: 3,200,000
- β Removing the mutex leads to silent data corruption
- π§ Core concept in all parallel programming, databases, and systems logic
Ready for [[08_atomic_counter_raceproof]]
next? I can format that one just as cleanly and push it to vault spec π