1.API详解
屏障(barrier)是协调多个线程并行工作的同步机制。屏障允许每个线程等待,知道所有的合并线程都到达某一点,然后从该点继续执行。可以看到,pthread_join函数就是一种屏障,但屏障的概念更加广泛,其允许任意数量的线程等待,直到所有线程完成处理工作阻塞在预先设置的点(也就是调用pthread_barrier_wait函数的地方),线程不需要退出。所有线程到达barrier后可以接着工作。
使用pthread_barrier_init函数对屏障进行初始化,用pthread_barrier_destroy进行反初始化。
#include<pthread.h>
int pthread_barrier_init(pthread_barrier_t *restrict barrier, const pthread_barrierattr_ty * restrict attr, unsigned int count);
int pthread_barrier_destroy(pthread_barrier_t *barrier);
//以上两个函数返回值:0:成功,否则,返回错误编号
int pthread_barrier_wait(pthread_barrier_t *barrier);
//返回值:若成功返回0或者PTHREAD_BARRIER_SERIAL_THREAD;否则返回错误编号
初始化时用count参数指定屏障计数值,在允许线程继续执行之前,必须到达屏障的线程数目。使用attr参数指定屏障的对象属性,这里使用默认值,设其为NULL。使用pthread_barrier_wait函数表明,当前线程已经完成工作,准备等待其他线程赶上来。调用pthread_barrier_wait函数的线程在屏障计数,如果未达到屏障计数值,当前线程会阻塞进入休眠状态。如果当前线程是最后一个调用pthread_barrier_wait,就满足了屏障计数,所有线程都被唤醒。
对于任意一个线程,pthread_barrier_wait函数返回了PTHREAD_BARRIER_SERIAL_THREAD。那么剩下的线程看到的返回值是0.这使得一个线程可以作为主线程,他可以工作在其他所有线程已完成工作的基础结果之上。
一旦达到屏障计数值,而且线程处于非阻塞状态,屏障就可以被重用。但是除非在调用了pthread_barrier_destroy函数之后,又调用pthread_barrier_init函数对计数用另外的值进行初始化,否则屏障计数不会改变。
2.实例
测试一:pthread_barrier_wait返回值PTHREAD_BARRIER_SERIAL_THREAD的唯一性与随机性。
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
struct thread_param
{
pthread_barrier_t *barrier;
int number;
};
void *thread_proc(void *lparam);
int main(int argc, char *argv[])
{
int ret;
pthread_t pthread[2];
pthread_barrier_t barrier;
thread_param lparam[2];
pthread_barrier_init(&barrier, NULL, 3);
lparam[0].barrier = &barrier;
lparam[1].barrier = &barrier;
for(int i = 0; i < 2; i++)
{
lparam[i].number = i;
pthread_create(&pthread[i], NULL, thread_proc, &lparam[i]);
}
//sleep(1);
ret = pthread_barrier_wait(&barrier);
if(PTHREAD_BARRIER_SERIAL_THREAD == ret) {
printf("the major thread barrier return PTHREAD_BARRIER_SERIAL_THREAD.\n");
} else if(0 == ret) {
printf("the major thread barrier return 0.\n");
}
sleep(2);
pthread_barrier_destroy(&barrier);
return 0;
}
void *thread_proc(void *lparam)
{
int ret;
thread_param *param = ((thread_param *)lparam);
printf("thread : %d\n", param->number);
ret = pthread_barrier_wait(param->barrier);
if(PTHREAD_BARRIER_SERIAL_THREAD == ret){
printf("the child thread : %d barrier return PTHREAD_BARRIER_SERIAL_THREAD.\n", param->number);
} else if(0 == ret) {
printf("the child thread : %d barrier return 0\n", param->number);
}
return NULL;
}
测试二:利用barrier的同步机制对八百万个数进行多线程分组排序。
#include <pthread.h>
#include <limits.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NTHR 8 /* number of threads */
#define NUMNUM 800 /* number of numbers to sort */
#define TNUM (NUMNUM/NTHR) /* number to sort per thread */
long nums[NUMNUM];
long snums[NUMNUM];
pthread_barrier_t barrier;
//堆排序相关接口
#define left(x) (2 * x + 1)
#define right(x) (2 * (x + 1))
void MaxHeapify(long* a, long i, long low, long high)
{
int l = left(i);
int r = right(i);
int largest;
int temp;
if (l <= high && a[l] > a[i]){
largest = l;
} else {
largest = i;
}
if (r <= high && a[r] > a[largest]){
largest = r;
}
if (largest != i){
temp = a[i];
a[i] = a[largest];
a[largest] = temp;
MaxHeapify(a, largest, low, high);
}
}
void BuildMaxHeap(long* a, long length)
{
for (int i = length / 2 - 1; i >= 0; i--){
MaxHeapify(a, i, 0, length - 1);
}
}
void HeapSort(long a[], long length)
{
int temp;
BuildMaxHeap(a, length);
for (int i = length - 1; i >= 1; i--){
temp = a[i];
a[i] = a[0];
a[0] = temp;
MaxHeapify(a, 0, 0, i - 1);
}
}
///
//线程处理函数
void *
thread_func(void *lparam)
{
long idx = (long)lparam;
//对该分组进行堆排序
HeapSort(nums + idx, TNUM);
//屏障
pthread_barrier_wait(&barrier);
return ((void *)0);
}
//合并各个分组的有序分数组
void
merge()
{
long idx[NTHR];
long i, sidx, minidx, num;
for(i = 0; i < NTHR; i++){
idx[i] = i * TNUM;
}
for(sidx = 0; sidx < NUMNUM; sidx++){
//理论上num应该设为无穷大
num = 10000000;
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]++;
}
}
int main(int argc, char *argv[])
{
unsigned long i;
pthread_t tid;
pthread_barrier_init(&barrier, NULL, NTHR + 1);
//初始化数组
for(i = 0; i < NUMNUM; i++){
nums[i] = rand() % NUMNUM;
}
//开辟NTHR(8)个子线程进行分组排序
for(i = 0; i < NTHR; i++){
pthread_create(&tid, NULL, thread_func, (void *)(i * TNUM));
}
pthread_barrier_wait(&barrier);
//合并各个分组的有序分数组
merge();
//将合并后的有序数组输出
for(i = 0; i < NUMNUM; i++){
printf("%ld ", snums[i]);
}
pthread_barrier_destroy(&barrier);
return 0;
}
自行粘贴代码后检验输出结果。