COP4610: Operating Systems & Concurrent Programming | up ↑ |
Suppose we want to design a solution to a version of the Barbershop Problem, starting from scratch. This can be approached in the following stages:
customer barber shop door set of waiting_chairs -- a queue for each chair: occupant set of barber_chairs for each chair: occupant
customer (waiting_at_door waiting_in_chair being_served none_of_these) barber (waiting_for_customer, working) shop door set of waiting_chairs (occupied unoccupied) set of barber_chairs (occupied unoccupied)
customer (active) barber (active) shop (passive) door set of waiting_chairs set of barber_chairs
customer ----- arrive_at_the_door barber ----- complete_haircut & start_new_haircut
customer: loop arrive_at_the_door; wait until can enter door; get into waiting chair; wait until a barber is ready; get out of waiting chair; get into barber chair; wait until barber is done cutting; leave the shop; end loop; barber: loop wait for a customer; start cutting hair; complete_haircut; end loop;
customer: loop arrive_at_the_door; *wait* until can enter door; (1) get into waiting chair; *wait* until a barber is ready; (2) get out of waiting chair; get into barber chair; *wait* until barber is done cutting; (3) leave the shop; end loop; barber: loop *wait* for a customer; (4) start cutting hair; complete_haircut; end loop;
customer: loop arrive_at_the_door; *wait* until can enter door; (1) get into waiting chair; *signal* barber that a customer is here; (3) *wait* until a barber is ready; (2) get out of waiting chair; *signal* someone else to come in the door; (1) get into barber chair; *wait* until barber is done cutting; (3) leave the shop; end loop; barber: loop *wait* for a customer; (4) *signal* a customer to come to the chair; (2) start cutting hair; complete_haircut; *signal* customer to leave shop; (3) end loop;
customer: loop pthread_mutex_lock (&M); arrive_at_the_door; *wait* until can enter door; (1) get into waiting chair; *signal* barber that a customer is here; (3) *wait* until a barber is ready; (2) get out of waiting chair; *signal* someone else to come in the door; (1) get into barber chair; *wait* until barber is done cutting; (3) leave the shop; pthread_mutex_unlock (&M); end loop; barber: loop pthread_mutex_lock (&M); *wait* for a customer; (4) *signal* a customer to come to the chair; (2) start cutting hair; complete_haircut; *signal* customer to leave shop; (3) pthread_mutex_unlock (&M); end loop;
customer: loop pthread_mutex_lock (&M); arrive_at_the_door; /* *wait* until can enter door; (1) */ while (no seats are available) pthread_cond_wait (&self.C, &M); get into waiting chair; *signal* barber that a customer is here; (3) /* *wait* until a barber is ready; (2) */ while (no barbers are available) pthread_cond_wait (&self.C, &M); get out of waiting chair; *signal* someone else to come in the door; (1) get into barber chair; /* *wait* until barber is done cutting; (3) */ while (barber is cutting) pthread_cond_wait (&self.C, &M); leave the shop; pthread_mutex_unlock (&M); end loop; barber: loop pthread_mutex_lock (&M); /* *wait* for a customer; (4) */ while (waiting_chairs_queue.empty) pthread_cond_wait (&self.C, &M); *signal* a customer to come to the chair; (2) start cutting hair; complete_haircut; *signal* customer to leave shop; (3) pthread_mutex_unlock (&M); end loop;
customer: loop pthread_mutex_lock (&M); arrive_at_the_door; /* *wait* until can enter door; (1) */ while (no seats are available) pthread_cond_wait (&self.C, &M); get into waiting chair; /* *signal* barber that a customer is here; (4) */ for (every barber) pthread_cond_signal (&barber.C); /* *wait* until a barber is ready; (2) */ while (no barbers are available) pthread_cond_wait (&self.C, &M); get out of waiting chair; /* *signal* someone else to come in the door; (1) */ for (every person at door) pthread_cond_signal (&person.C); get into barber chair; /* *wait* until barber is done cutting; (3) */ while (barber is cutting) pthread_cond_wait (&self.C, &M); leave the shop; pthread_mutex_unlock (&M); end loop; barber: loop pthread_mutex_lock (&M); /* *wait* for a customer; (4) */ while (waiting_chairs_queue.empty) pthread_cond_wait (&self.C, &M); mycustomer = waiting_chairs_queue.dequeue; /* *signal* mycustomer to come to the chair; (2) */ pthread_cond_signal (&mycustomer.C); start cutting hair; complete_haircut; /* *signal* customer to leave shop; (3) */ pthread_cond_signal (&mycustomer.C); pthread_mutex_unlock (&M); end loop;
customer barber is_cutting : boolean door -- a queue waiting_chairs -- a queue customer: loop pthread_mutex_lock (&M); arrive_at_the_door; door.enqueue(self); while (waiting_chairs.is_full) pthread_cond_wait (&self.C, &M); door.dequeue(self); waiting_chairs.enqueue(self); for (every barber) pthread_cond_signal (&barber.C); while (no barbers are available) pthread_cond_wait (&self.C, &M); waiting_chairs.dequeue(self); person = door.dequeue(); pthread_cond_signal (&person.C); get into barber chair; while (barber is cutting) pthread_cond_wait (&self.C, &M); leave the shop; pthread_mutex_unlock (&M); end loop; ---------------------- barber: loop pthread_mutex_lock (&M); while (waiting_chairs.is_empty()) pthread_cond_wait (&self.C, &M); mycustomer = waiting_chairs.dequeue(); pthread_cond_signal (&mycustomer.C); start cutting hair; complete_haircut; pthread_cond_signal (&mycustomer.C); pthread_mutex_unlock (&M); end loop;
etc.
customer entering shop: ...assume mutex M is locked here... /* take a number; */ mynumber = takenumber; takenumber++; while (mynumber != servednumber) pthread_cond_wait (&self.C, &M); ...mutex M is locked again here... another customer leaving waiting chair: servednumber++; for (every customer at door) pthread_cond_signal (&customer.C);
What is wrong with this?
pthread_cond_wait (&C, &M) has the effect of: pthread_mutex_unlock (&M); sleeps until some random wakeup or pthread_cond_signal is called for C pthread_mutex_lock (&M); but the first tww steps are ATOMIC
int ferry_shore_volunteer () { passenger_ptr self = get_current_thread_record(); pthread_mutex_lock (&M); if not_in_queue (self, shore_queue[self->side]) put_in_queue (self, shore_queue [self->side]); ferry_update_state (); while (self->should_wait) pthread_cond_wait (&(self->CV), &M); pthread_mutex_unlock (&M); if (self->pulling) return 0; else return 1; } int ferry_board_volunteer () { passenger_ptr self = get_current_thread_record(); pthread_mutex_lock (&M); if not_in_queue (self, boat_queue) put_in_queue (self, boat_queue); ferry_update_state (); while (self->should_wait) pthread_cond_wait (&(self->CV), &M); pthread_mutex_unlock (&M); if (self->pulling) return 0; else return 1; } void ferry_update_state (passenger_ptr self) { int state_changed = 1; while (state_changed) { switch (ferry.state) { ... ... if discover a thread t should wake up, pthread_cond_signal (&(t->CV)); ... } } }
This just a pseudo-code sketch of one way of coding a solution to this problem. Please don't slavishly try to copy the above.
T. P. Baker. ($Id) |