屏障 (Barrier) 允許每個線程都處於等待狀態,直到所有的合作線程都達到某一執行點,然後從該點繼續執行。pthread_join(tid)
就是一種最簡單的「屏障」行爲,允許當前線程等待 tid
線程的完成。
Barrier 的範圍更廣,它允許任意數量的線程處於等待狀態,直到所有線程完成工作,而線程不需要退出,所有線程到達 Barrier 後可以繼續執行。
API
相關數據結構:
pthread_barrier_t
:屏障的數據結構;pthread_barrierattr_t
:屏障屬性的數據結構。
init and destroy
函數原型:
int pthread_barrier_destroy(pthread_barrier_t *barrier);
int pthread_barrier_init(pthread_barrier_t *restrict barrier,
const pthread_barrierattr_t *restrict attr, unsigned count);
作用:初始化/銷燬 barrier
.
count
參數表示在允許所有線程繼續執行前,必須達到 barrier 的線程的數量。
wait
函數原型:
int pthread_barrier_wait(pthread_barrier_t *barrier);
返回值:若成功,返回 0 或者 PTHREAD_BARRIER_SERIAL_THREAD(-1)
, 其中有且只有一個線程會返回 PTHREAD_BARRIER_SERIAL_THREAD
,其餘返回 0 ,返回 PTHREAD_BARRIER_SERIAL_THREAD
的線程可以作爲主線程,處理、合併其他線程的工作;失敗則返回錯誤碼。
作用:使得 barrier 的計數加一,如果不滿足條件(即計數結果未達到初始化時設定的 count
),線程進入 sleep 休眠狀態。如果當前線程調用 wait
後,滿足了 barrier 條件,那麼在該 barrier 上等待的所有線程都將被喚醒。
Example
多線程排序,在主線程合併。
#include <pthread.h>
#include <stdio.h>
#include <sys/time.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>
#define NTHR 8
#define N 8000000L
#define TNUM (N / NTHR)
int nums[N] = {0};
int snums[N] = {0};
pthread_barrier_t barrier;
int x = 0;
int cmp(const void *a, const void *b)
{
int x = *(int *)a;
int y = *(int *)b;
return x - y;
}
void merge()
{
uint64_t idx[NTHR];
uint64_t i, minidx, sidx;
int num;
for (i = 0; i < NTHR; i++) idx[i] = i * TNUM;
for (sidx = 0; sidx < N; sidx++)
{
num = 0x7fffffff;
for (i = 0; i < NTHR; i++)
{
if ((idx[i] < (i + 1) * TNUM) && (nums[idx[i]] < num))
{
num = nums[idx[i]];
minidx = i;
}
}
snums[sidx] = nums[idx[minidx]];
idx[minidx]++;
}
}
void *worker(void *args)
{
uint64_t idx = (u_int64_t)args;
qsort(&nums[idx], TNUM, sizeof(int), cmp);
pthread_barrier_wait(&barrier);
return NULL;
}
int main()
{
int i = 0, ret = 0;
pthread_t tid;
// init numbers array
srandom(time(NULL));
for (i = 0; i < N; i++)
nums[i] = random() % 100;
// init barrier
pthread_barrier_init(&barrier, NULL, NTHR + 1);
// create NTHR threads
for (i = 0; i < NTHR; i++)
{
ret = pthread_create(&tid, NULL, worker, (void *)(i * TNUM));
if (ret != 0)
{
puts(strerror(ret));
exit(ret);
}
}
// wait here
pthread_barrier_wait(&barrier);
merge();
pthread_barrier_destroy(&barrier);
// check whether if increase order
for (i = 1; i < N; i++)
assert(snums[i] >= snums[i - 1]);
// print sorted result
// for (i = 0; i < N; i++)
// printf("%d%c", snums[i], i == N - 1 ? '\n' : ' ');
return 0;
}