SPThreads 4 Cond
SPThreads 4 Cond
Ion Mandoiu
Laurent Michel
Revised by M. Khan and J. Shi
Mutex Review
• Mutex
• One has to get the lock before entering critical section
• Yields exclusive access to a resource
• If a thread cannot get the lock, it waits …
• Example of two threads sharing data
• Thread 1 computes a result
• Thread 2 displays the result on UI when computation done
• Question
How does thread 2 know the result is ready?
2
Producer-Consumer with Bounded Buffer
• Classic problem
• Producer(s) put things into a shared buffer
• Consumer(s) take them out!
3
Problem Constraints
• Mutual exclusion
• Only one thread can manipulate the buffer at any time
• Buffer is shared!
• Synchronization
• Consumer(s) must WAIT if buffer is empty
• Producer(s) must WAIT if buffer is full
4
Well…. Sorta…
Consumer in pseudo-code
do {
Lock the buffer // Buffer is shared ! May have to wait
if buffer is not empty
Fetch data in the buffer
Unlock the buffer
} while (data is not fetched) // May fail, so try in a loop
Process the data
5
Consumer in C-like code
pthread_mutex_t buffer_lock;
// Consumer fetches data from a buffer, one each time.
fetched = 0;
do {
pthread_mutex_lock(& buffer_lock); // Get the lock for the buffer
if (nElements > 0) { // If the buffer is not empty
data = fetch_from_buffer(); // Fetch data from the buffer
fetched = 1;
}
pthread_mutex_unlock(& buffer_lock);
} while (fetched == 0);
// Continue to process data
7
Consumer waits on condition
pthread_mutex_t buffer_lock;
// Consumer fetches data from a buffer, one each time.
8
Consumer waits on condition - 2
It is a while, not if
A predicate
10
pthread_cond API
#include <pthread.h>
11
Tips
12
Typical structure of using mutex and condition
pthread_mutex_t mutex;
pthread_cond_t cond; // mutex and cond are defined somewhere
13
Example setup
• Assumptions
• A buffer that can hold only one item
• A predicate P, indicating if the data is ready for consumer
• A POSIX condition variable
• A POSIX mutex
• Threads
T1: producer T2: consumer
Can be many threads: 1 .. k
14
Two scenarios
• Scenario 1
• The producer gets to produce…
• …before the consumer consumes the previous one
• Scenario 2
• The consumer is eager and tries to consume…
• …before the producer gets a chance to produce
15
Scenario 1 : eager producer
16
Storyboard
T1 TIME T2
Shared
Data
P
True
t e x
u
m
Condition C
Data is ready
P is True
T1 tries to place new data
17
Storyboard
T1 TIME T2
Shared
Data
CS P
True
t e x
u
m
Condition C
T1 enters CS
mutex is locked
18
Storyboard
T1 TIME T2
Shared
Data
CS P
while (P) wait(C,m) True
t e x
u
m
Condition C
Buffer is full
T1 waits on C
19
Storyboard
T1 TIME T2
Shared
Data
CS P
while (P) wait(C,m) True
t e x
u
m
Condition C
T2 to consume
enters CS
21
Storyboard
T1 TIME T2
Shared
Data
CS P
while (P) wait(C,m) False
t e x
u
m
CS
Fetch data
Change P Condition C
signal(C)
Data fetched
T2 sends signal,
even if nobody is waiting 22
Storyboard
T1 TIME T2
Shared
Data
CS P
while (P) wait(C,m) False
t e x
u
m
CS
Fetch data
Change P Condition C
signal(C)
Process data
T2 unlock()
23
Storyboard
T1 TIME T2
Shared
Data
CS P
while (P) wait(C,m) False
t e x
u
m
CS
Fetch data
Change P Condition C
signal(C)
Process data
Continue to produce T1 gains the lock
24
Scenario 2 (Eager consumer)
25
Storyboard
T1 TIME T2
Shared
Data
P
False
t e x
u
m
Condition C
Buffer is empty
26
Storyboard
T1 TIME T2
Shared
Data
CS P
False
t e x
u
m
Condition C
Condition C
T2 has to wait!
wait() unlocks mutex
28
Storyboard
T1 TIME T2
Shared
Data
CS P
while (!P) wait(C,m) False
t e x
CS u
m
Condition C
Data is ready
T1 sends signal
even if no one is waiting 30
Storyboard
T1 TIME T2
Shared
Data
CS P
while (!P) wait(C,m) True
t e x
CS u
Set data m
Change P
signal(C)
Condition C
Mutex unlocked
31
Storyboard
T1 TIME T2
Shared
Data
CS P
while (!P) wait(C,m) True
t e x
CS u
Set data m
Change P
signal(C)
Condition C
CS
Continue to consume T2 wakes up
and continues
32
Signal vs. Broadcast
pthread_cond_signal(pthread_cond_t *cond);
• Wakes up one waiting thread in the condition
pthread_cond_broadcast(pthread_cond_t *cond);
• Wakes up all waiting threads in the condition
• Yet, only one of the waiting threads can grab the mutex
• Go back to sleep if it fails
Caveat: a thread calling wait after the broadcast will not wake up (even if others in
the process of waking up are still stuck in the condition variable — e.g., waiting
on getting the mutex lock —)
33
Study the remaining slides yourself
34
Producer in pseudo-code
Prepare data
do {
Lock the buffer // May have to wait
if buffer is not full// For bounded buffer
Put data in the buffer
Unlock the buffer
} while (data is not placed in the buffer)
35
Producer in C-like code
pthread_mutex_t buffer_lock;
// Producer adds data in a buffer, one each time.
…… // Prepare data here
added = 0;
do {
pthread_mutex_lock(& buffer_lock); // Get the lock for the buffer
if (nElements < BUF_SIZE) { // If the buffer is not full
add_to_buffer (data); // Add data into the buffer
added = 1;
}
pthread_mutex_unlock(& buffer_lock);
} while (added == 0);
37
Producer-Consumer Using Condition Variables
void *producer(void *producer_thread_data)
{
int inserted;
while (!done()) {
create_task(); // time-consuming step, before locking the mutex
pthread_mutex_lock(&task_queue_cond_lock);
while (task_available == 1) // wait in a loop!
pthread_cond_wait(&cond_queue_empty,&task_queue_cond_lock);
insert_into_queue(); // access shared resources
task_available = 1; // update the predicate
pthread_cond_signal(&cond_queue_full);
pthread_mutex_unlock(&task_queue_cond_lock);
}
}
38
Producer-Consumer Using Condition Variables
void *consumer(void *consumer_thread_data)
{
while (!done()) {
pthread_mutex_lock(&task_queue_cond_lock);
while (task_available == 0) // wait in a loop!
pthread_cond_wait(&cond_queue_full,&task_queue_cond_lock);
my_task = extract_from_queue();
task_available = 0; // update the predicate
pthread_cond_signal(&cond_queue_empty);
pthread_mutex_unlock(&task_queue_cond_lock);
process_task(my_task); // this is after unlocking mutex
}
}
39