260 likes | 414 Views
Thread Synchronization. Tutorial #8 CPSC 261. A thread is a virtual processor. Each thread is provided the illusion that it owns a core Copy of the registers It is running all the time Programs involving threads tend to have to solve some synchronization problems. The problems.
E N D
Thread Synchronization Tutorial #8 CPSC 261
A thread is a virtual processor • Each thread is provided the illusion that it owns a core • Copy of the registers • It is running all the time • Programs involving threads tend to have to solve some synchronization problems
The problems • The bounded buffer that we have talked about is an example of a “classic” synchronization problem • Also known as the producer/consumer problem
Producer/Consumer Producers Consumers receive() send() Bounded buffer
Producer/Consumer constraints • Each message sent by a producer is received by exactly one consumer • Each message received by a consumer was sent by a producer • There are never more than N messages in the bounded buffer (the bound is N) • Liveness – the system “makes progress”
Readers/Writers Readers Writers read() write() Resource
Readers/Writers constraints • There can be either k readers (k >= 1) or 1 writer using the resource at any instant in time
Variation #1 • Reader priority • No reader waits any longer than absolutely necessary
Variation #2 • Writer priority • No writer waits any longer than absolutely necessary
Variation #3 • Fairness • The order in which threads first attempt to access the resource determines the order in which readers/writers get access to the resource • No thread will starve – eventually each thread will access the resource no matter what other threads exist or what they do
Sleeping Barber Waiting Room Customers Barber
Sleeping Barber constraints • The barber cuts one customer’s hair at a time • When the barber finishes cutting hair: • The first arriving customer moves to the barber chair and gets his hair cut • If there are no customers, the barber goes to sleep
Sleeping Barber constraints II • Customers arrive at arbitrary times: • If the barber chair is empty the customer sits in the barber chair • If the barber is sleeping, he wakes up and gets to work • If the barber chair is full, the customer sits in an empty chair in the waiting room • If there are no empty chairs the customer just leaves
Sleeping Barber constraints III • Liveness • Fairness
Dining philosophers constraints • Never-emptying plate of spaghetti on the table • 5 forks on the table one between each pair of philosophers • Each philosopher needs 2 forks to eat spaghetti • They will only use the forks on their immediate left and immediate right • Each philosopher: • Think, eat, think, eat, ... • Philosophers don’t care about hygiene
Variation #1 • The classical problem: • Left then right • The philosopher first picks up the fork on his immediate left • Then picks up the fork on his immediate right • Then eats • Then puts down both forks (order doesn’t matter)
Variation #2 • The resource ordering problem: • There is a total order on forks (they are numbered 0 – 4) • The philosopher first picks up the fork with the lower number (among his left and right forks) • Then picks up the fork with the higher number • Then eats • Then puts down both forks (order doesn’t matter)
Variation #3 • The random problem: • The philosopher first randomly picks up either his left fork or his right fork • If it isn’t on the table, he gives up and starts over • Then picks up the other fork • If it isn’t on the table, he gives up, puts down the first fork, and starts over • Then eats • Then puts down both forks (order doesn’t matter)
Your task • Implement these 3 variations of the dining philosophers problem
Your tools • Pthreads • 1 thread for each philosopher • PthreadsMutexes • Pthreads condition variables • Semaphores
Pthreadsmutexes • created as all other objects (malloc) • initialized by pthread_mutex_init() • acquired by pthread_mutex_lock() • released by pthread_mutex_unlock()
Pthreads condition variables • created as all other objects (malloc) • initialized by pthread_cond_init() • wait by pthread_cond_wait() • wait always occurs in a loop, checking the condition each time around • signal by pthread_cond_signal()
Pthreads semaphores • created as all other objects (malloc) • initialized by sem_init() • wait by sem_wait() • post by sem_post()
Hints • Think a little bit about data structures: • How are you going to represent each fork? • What thread synchronization constructs are you going to need? • How are you going to convince yourself (and eventually me and the TAs) that your solution is correct? • Print trace messages about what is going on
A sample trace $ ./phil-ordered 1: got left fork 2: got left fork 2: got right fork 2: eat 2: put back right fork 2: put back left fork 3: got left fork 0: got left fork 2: got left fork 3: got right fork 3: eat 3: put back right fork 3: put back left fork ...