π₯ Asymmetric. Realistic. Glitch-prone. Educational. This is exactly the kind of multithreaded artifact that deserves vault-tier documentation β especially under [[asymmetric_pthreads/09_producer_consumer_condition_var]]
.
π 09_producer_consumer_condition_var
π§΅ Classic 1-buffer producer/consumer using
pthread_cond_t
andmutex
π§ One of the only βsafeβ real-world uses ofwhile
in multithreading.
π Mess it up, and you get deadlocks, missed signals, or race conditions you canβt debug.
π§ Problem: Shared Finite Buffer
-
π¨βπ³ Producer: creates
ITEM_COUNT
items (100) -
π¨βπ©βπ§ Consumer: consumes each item with delay
-
π¦ Shared buffer of size
10
-
β οΈ Critical section = insertion/removal of item
-
π Protected by:
-
pthread_mutex_t mutex
-
pthread_cond_t cond_full
-
pthread_cond_t cond_empty
-
π¦ Buffer Logic
int buffer[BUFFER_SIZE];
int count = 0;
π‘ Invariants
Rule | Meaning |
---|---|
count == 0 | Buffer is empty |
count == BUFFER_SIZE | Buffer is full |
0 < count < BUFFER_SIZE | Safe to read/write |
π§ put_item / get_item
void put_item(int item)
{
buffer[count] = item;
count++;
}
int get_item(void)
{
int item = buffer[count - 1];
count--;
return item;
}
β οΈ LIFO behavior.
Youβre technically consuming from the top of a stack, not a FIFO queue.
This is not a circular queue. (But perfect for demoing condition variables.)
π§ͺ How It Works
π¨βπ³ Producer
while (count == BUFFER_SIZE)
pthread_cond_wait(&cond_empty, &mutex);
put_item(i);
pthread_cond_signal(&cond_full);
-
π₯ Waits if buffer full
-
π§
while
is essential β thread might get woken up by spurious signal -
π§ Signals consumer when item available
π¨βπ©βπ§ Consumer
while (count == 0)
pthread_cond_wait(&cond_full, &mutex);
item = get_item();
pthread_cond_signal(&cond_empty);
-
π₯ Waits if buffer empty
-
π§ Wakes up only when something to consume
-
π§ Signals producer once space is freed
β Delay Design
#define PRODUCE_DELAY_US 1000
#define CONSUMER_DELAY_US 5000
-
β³ Producer is faster than consumer (1ms vs 5ms)
-
π¦ Buffer fills up fast, forcing
pthread_cond_wait
β great for demonstrating real blocking
π¬ Terminal Output (Sample)
Produced 0 (count=1)
Produced 1 (count=2)
...
Produced 9 (count=10)
Consumed 9 (count=9)
Produced 10 (count=10)
...
π§ Youβll notice:
-
Buffer hits max (
count=10
) -
Producer blocks
-
Consumer unblocks it with signal
-
Then it continues
π Visually traceable buffer occupancy
β οΈ Failure Modes (If You Do It Wrong)
π₯ Error | π Consequence |
---|---|
Use if instead of while | Spurious wake = buffer overrun or underrun |
No pthread_mutex_lock | Race condition = buffer corruption |
Forget to signal | Deadlock forever |
Stack instead of queue | Not FIFO β Logic flaw |
Call put_item outside lock | Undefined behavior, maybe SIGSEGV |
π§ Why This Is Asymmetric
title: Asymmetry Factors
- β±οΈ Designed delays reveal real-time sync issues
- π§ Showcases *waiting*, not just mutual exclusion
- π οΈ Threads are reactive β not just aggressive
- π If you remove one `signal()` or change `while` to `if`, deadlock creeps in silently
- π€ Feels stable but is one mistake away from chaos
π Suggested Upgrades
π§ [[asymmetric_pthreads/09b_fifo_ringbuffer_condvar.c]]
β Convert to true circular queue
π§ [[asymmetric_pthreads/09c_multi_producer_consumer_pool.c]]
β Expand to thread pool (n producer, m consumer)
π₯ [[asymmetric_pthreads/09d_condvar_lost_signal_demo.c]]
β Show condition variable signal *missed* β thread starves
π§ TL;DR Summary
title: Key Concepts
- π§΅ Real-world use of `pthread_cond_t`
- π§ `while` protects from spurious wakeups
- π Always pair `pthread_cond_wait` with a `pthread_mutex`
- π Buffer state transitions: full β wait β empty β wait
- π£ Critical section correctness matters more than speed
Ready to build [[09b_fifo_ringbuffer_condvar.c]]
next?
Or want to inject an artificial deadlock to show what happens with a missing signal?