When I was porting the mbw to the OSX, I found that pthread_barrier_t and related functions are missing. Fortunately it is not hard to implement barriers based on pthread_mutex_t and pthread_cond_t. Usually barriers are used to ensure that all threads have finished the current step before they can proceed to the next step. The threads finished fast have to wait other slow threads to catch up. In this example, I am going to use the sense-reverse barrier which is probably the easiest to implement.

The pthread_barrier_t contains a mutex protecting the whole data structure and associated with the conditional variable. The flag changes every time when the number of threads calling the pthread_barrier_wait is equal to the number specified by the num variable which is set during initialisation. Finally the count field records the number of threads have arrived at the barrier, and if it equals num, all threads have arrived and they may pass the barrier.

The init function is pretty straightforward, so let us focus on the wait funciton. The first step is to acquire the mutex which protects the whole barrier. Then a thread saves the flag in its local variable and increases the count varibles. If the count equals to num, it means that the calling thread is the last thread which needs to wake up other waiting threads. The last thread resets the barrier counter to 0 and changes the barrier flag to a different value. After that, the pthread_cond_broadcast is used wake up other threads while the thread is holding the mutex. On the other hand, other threads called wait function early execute pthread_cond_wait to block themselves. After they are woken up by the last thread, they check if the barrier flag value is different from the value saved locally and exit the loop if so.

#define PTHREAD_BARRIER_SERIAL_THREAD   1

typedef struct pthread_barrier {
  pthread_mutex_t         mutex;
  pthread_cond_t          cond;
  volatile uint32_t       flag;
  size_t                  count;
  size_t                  num;
} pthread_barrier_t;

int pthread_barrier_init(pthread_barrier_t *bar, int attr, int num)
{
  int ret = 0;
  if ((ret = pthread_mutex_init(&(bar->mutex), 0))) return ret;
  if ((ret = pthread_cond_init(&(bar->cond), 0))) return ret;
  bar->flag = 0;
  bar->count = 0;
  bar->num = num;
  return 0;
}

int pthread_barrier_wait(pthread_barrier_t *bar)
{
  int ret = 0;
  uint32_t flag = 0;

  if ((ret = pthread_mutex_lock(&(bar->mutex)))) return ret;

  flag = bar->flag;
  bar->count++;

  if (bar->count == bar->num) {
    bar->count = 0;
    bar->flag = 1 - bar->flag;
    if ((ret = pthread_cond_broadcast(&(bar->cond)))) return ret;
    if ((ret = pthread_mutex_unlock(&(bar->mutex)))) return ret;
    return PTHREAD_BARRIER_SERIAL_THREAD;
  }

  while (1) {
    if (bar->flag == flag) {
      ret = pthread_cond_wait(&(bar->cond), &(bar->mutex));
      if (ret) return ret;
      } else { break; }
    }

  if ((ret = pthread_mutex_unlock(&(bar->mutex)))) return ret;
  return 0;
}