UNIVERSITY OF WISCONSIN-MADISON
Computer Sciences Department
CS 537
Fall 2007
A. Arpaci-Dusseau
Quiz #6: Take-home: Due Oct 18, 2007
Name:

Critical Sections

The following code specifies different implementations for a lock. Assume that the application calls lock_init() before using the lock and calls lock_acquire() before entering the critical section and lock_release() after exiting the critical section. Assume that the tid of each thread is either 0 or 1. Assume a uniprocessor.

  1. For each of the two code sample, does the code correctly protect a critical section?
  2. If the implementation is not correct, list a critical section requirement that is violated.
  3. If the implementation is not correct, show a sample interleaving of C statements (within the lock_acquire() and lock_release() routines) across two threads that leads to that problem. Clearly designate which thread is executing each stream of instructions.

typedef int lock_t;
lock_init(lock_t *flag) {
   *flag = 0;
}
void lock_acquire(lock_t *flag) {
   while (*flag);
   *flag = 1;
}
void lock_release(lock_t *flag) {
   *flag = 0;
}
typedef struct {
   int turn;
   int flag[2];
} lock_t;
lock_init(lock_t *myl) {
   myl->turn = 0;
   myl->flag[0] = myl->flag[1] = 0;
}
void lock_acquire(lock_t *myl) {
   myl->flag[tid] = 1;
   myl->turn = 1-tid;
   if (tid == 0) {
       while (myl->flag[1] && myl->turn == 1);
    } else { /* tid == 1 */
       while (myl->flag[0]);
    }
}
void lock_release(lock_t *myl) {
   myl->flag[tid] = 0;
} 

Dining Philosophers with Condition Variables

Below is code that solves the Dining Philosopher problem such that it is live as well as safe; this is done with the addition of a state variable for each philosopher, designating whether they are THINKING, EATING, or HUNGRY. This code works correctly (assuming it is initialized appropriately). Assume that each philosopher thread alternates between thinking, calling take_chopsticks, eating, and calling put_chopsticks. Assume that each thread has a variable tid that is set correctly.

You should assume that locks and condition variables have been implemented correctly with Mesa semantics.


cv_t mayEat[5];                // How is this initialized?
lock_t lock;                   // A monitor lock -- initialized to unlock'ed!
volatile int state[5];         // Initialized to THINKING

void take_chopsticks() {
     lock_acquire(&lock);
     state[tid] = HUNGRY;
     test(tid);
     while (state[tid] != EATING) {
         cv_wait(&mayEat[tid], &lock);
     }
     lock_release(&lock);
}

void put_chopsticks() {
     lock_acquire(&lock);
     state[tid] = THINKING;
     test(tid+1%5);
     test(tid+4%5);
     lock_release(&lock);
}

void test(int i) {
     if (state[i]==HUNGRY && state[i+1%5]!=EATING && state[i+4%5]!=EATING) {
          state[i] = EATING;
          cv_signal(&mayEat[i]);
     }
}

How should the condition variable elements of mayEat be initialized?





What is the maximum number of Philosophers that can be waiting on lock at any given time?



What is the maximum number of Philosophers that can be waiting on one condition variable element mayEat[i] in the array mayEat at any given time?

Why does the lock need to be passed to the routine cv_wait(&mayEat[tid], &lock)? Give an example execution where something would go wrong without it.







Does the code work correctly if the expression while (state[tid] != EATING) is removed before the statement cv_wait(&mayEat[tid], &lock)? Briefly describe why or why not.







Does the code work correctly if the expression while (state[tid] != EATING) is changed to if (state[tid] != EATING)? Briefly describe why or why not. Be sure to think this one through carefully!







Does the code work correctly if instead of an array of condition variables, mayEat[i], every philosopher waits and signals on one shared condition variable, someoneMayEat? Briefly describe why or why not.







Assume that in addition to using just one condition variable, someoneMayEat, the cv_signal(mayEat[i]) is changed to cv_broadcast(someoneMayEat). (Hint: cv_broadcast wakes all threads waiting on the specified condition variable.) Does the code work correctly? Briefly describe why or why not.