Select Page

As always, download barrier.c and read it.

main() creates argv[1] number of Pthreads. Each thread does:

static void *
thread(void *xa)
{
  long n = (long) xa;
  long delay;
  int i;

  for (i = 0; i < 20000; i++) {
    int t = bstate.round;
    assert (i == t);
    barrier();
    usleep(random() % 100);
  }
}

Threads should block in barrier() until all threads have called barrier(). bstate is defined as:

struct barrier {
  pthread_mutex_t barrier_mutex;
  pthread_cond_t barrier_cond;
  int nthread;      // Number of threads that have reached this round of the barrier
  int round;     // Barrier round
} bstate;

Without further ado, here’s my solution:

static void 
barrier()
{
  pthread_mutex_lock(&bstate.barrier_mutex);

  if (++bstate.nthread < nthread) {
    pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex);
  }
  else {
    bstate.nthread = 0;
    bstate.round++;
    pthread_cond_broadcast(&bstate.barrier_cond);
  }

  pthread_mutex_unlock(&bstate.barrier_mutex);
}

Fairly simple. Whenever a thread calls barrier(), it increments bstate.nthread. If bstate.nthread reaches nthread, the current thread is responsible to wakeup all other threads (by calling pthread_cond_broadcast()), set bstate.nthread back to zero and increment bstate.round. Otherwise, the thread simply calls pthread_cond_wait() then goes to sleep.

Of course, since bstate is a global structure, all these read/write accesses to it need to be done while holding a mutex lock acquired by calling pthread_mutex_lock().

Let’s run it:

peilin@PWN:~/6.828/2018/homework/barriers$ make
gcc -g -O2 -pthread -o barrier barrier.c
peilin@PWN:~/6.828/2018/homework/barriers$ ./barrier 10
OK; passed

OK;…

Finally let’s take a look at two more issues mentioned in the homework page:

You have to deal with a succession of barrier calls, each of which we’ll call a round. bstate.round records the current round. You should increase bstate.round when each round starts.

Homework: Barriers

Emm yeah, I believe so, starting from zero. My implementation passed that assert statement in thread().

You have to handle the case in which one thread races around the loop before the others have exited the barrier. In particular, you are re-using bstate.nthread from one round to the next. Make sure that a thread that leaves the barrier and races around the loop doesn’t increase bstate.nthread while a previous round is still using it.

Homework: Barriers

Say we have two threads, A and B. A was waiting, then B waked it up. Now bstate.nthread is set back to zero. Suppose B now just keep on running for no reason. Theoretically, how far can B run ahead of A? It can return from barrier(), jump into the next iteration of for loop, call barrier() again, increment bstate.nthread to one, then it will wait – since nthread > 1… Nothing to worry about!

That’s pretty much it. See you next time!