Wiki:
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个线程通过了这个函数。