libuv中的Barrier

Wiki:Barrier

In parallel computing, a barrier is a type of synchronization method. A barrier for a group of threads or processes in the source code means any thread/process must stop at this point and cannot proceed until all other threads/processes reach this barrier.

简言之就是要等到指定数目的线程一起到达才能一起继续执行。

libuv中对于barrier结构的定义:

typedef struct {
  unsigned int n;              //对于当前等待线程的计数
  unsigned int count;        //设置的总数
  uv_mutex_t mutex;        //结构体内操作同步用
  uv_sem_t turnstile1;        //turnstile意为旋转门,这里1和2分别表示一起进和一起出
  uv_sem_t turnstile2;
} uv_barrier_t;

初始化

int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
  int err;

  barrier->n = count;
  barrier->count = 0;

  err = uv_mutex_init(&barrier->mutex);
  if (err)
    return err;

  err = uv_sem_init(&barrier->turnstile1, 0);
  if (err)
    goto error2;

  err = uv_sem_init(&barrier->turnstile2, 1);
  if (err)
    goto error;

  return 0;

error:
  uv_sem_destroy(&barrier->turnstile1);
error2:
  uv_mutex_destroy(&barrier->mutex);
  return err;

}

销毁

void uv_barrier_destroy(uv_barrier_t* barrier) {
  uv_sem_destroy(&barrier->turnstile2);
  uv_sem_destroy(&barrier->turnstile1);
  uv_mutex_destroy(&barrier->mutex);
}

接下来是最重要的代码:

 1 int uv_barrier_wait(uv_barrier_t* barrier) {
 2   int serial_thread;
 3 
 4   uv_mutex_lock(&barrier->mutex);
 5   if (++barrier->count == barrier->n) {
 6     uv_sem_wait(&barrier->turnstile2);
 7     uv_sem_post(&barrier->turnstile1);
 8   }
 9   uv_mutex_unlock(&barrier->mutex);
10 
11   uv_sem_wait(&barrier->turnstile1);
12   uv_sem_post(&barrier->turnstile1);
13 
14   uv_mutex_lock(&barrier->mutex);
15   serial_thread = (--barrier->count == 0);
16   if (serial_thread) {
17     uv_sem_wait(&barrier->turnstile1);
18     uv_sem_post(&barrier->turnstile2);
19   }
20   uv_mutex_unlock(&barrier->mutex);
21 
22   uv_sem_wait(&barrier->turnstile2);
23   uv_sem_post(&barrier->turnstile2);
24   return serial_thread;
25 }

当没有达到设置的阈值的时候,代码直接通过4-9行,在11行阻塞。直到指定数目的线程到达,进入4-9行,将第一扇门打开(turnstile1变为1),第二扇门关上(turnstile2变为0)。

然后刚才等待在第一扇门的第一个线程就可以通过11行,当这个线程通过后(此时turnstile变为0),再将turnstile置为1,让后一个线程可以通过。当前线程通过14-20行(此时barrier->count已变为最大值),会等待在22行。

当最后一个线程都通过了14行后,会进入16行的判断块内,此时它将第一扇门关上,第二扇门打开(turnsatile1变为0,turnsatile2变为1)。此时所有等在22行线程都可以继续执行,还是同过第一扇门的时候相同,它们是一个个接力过第二扇门的。

至此,所有线程全部通过了这两扇门。

思考:为什么需要14行后的代码,当凑齐数目后一起通过不是就完成任务了么?为什么还要一起出这个函数呢?

如果不加后面逻辑,考虑下面的情况。
当N个线程全部到达第一扇门后,有两个线程出了这个函数。这个时候又有第N+1线程到达这个函数了,那么最终这第N+1个线程,也会一起出这个函数,那么总共有N+1个线程通过了这个函数。
View Code

 

posted @ 2016-06-20 16:48  小白兔纸白又白  阅读(914)  评论(0编辑  收藏  举报