屏障
int pthread_barrier_init(pthread_barrier_t *restrict barrier,
const pthread_barrierattr_t *restrict attr,
unsigned count);
int pthread_barrier_destroy(pthread_barrier_t *barrier);
int pthread_barrier_wait(pthread_barrier_t *barrier);
屏障允许任意数量的线程等待, 直到所有的线程完成处理工作, 而线程不需要退出, 所有线程达到屏障之后可以接着工作.
init:在初始化屏障时, 可以使用第三个参数count指定, 在允许所有线程继续运行之前, 必须到达屏障的线程数目.
wait:可以使用pthread_barrier_wait函数来表明, 线程已经完成工作, 准备等所有其他线程赶上来;
调用wait的线程在屏障计数未满足条件时, 会进入休眠状态. 如果该线程是最后一个调用wait的线程, 就满足了屏障计数, 所有的线程都被唤醒.
对于一个任意线程, pthread_barrier_wait函数返回了PTHREAD_BARRIER_SERIAL_THREAD. 剩下的线程看到的返回值是0. 这使得一个线程可以作为主线程, 他可以工作在其他所有线程已完成的工作结果上.
单线程与多线程排序
单线程排序
bool compare(long a, long b)
{
return a < b;
}
#define NUMNUM 8000000L
long int nums[NUMNUM]; //待排序数组(约32M)
int main()
{
srandom(time(NULL));
for (unsigned long i = 0; i < NUMNUM; i++)
nums[i] = random();
struct timeval start, end;
//计时开始
gettimeofday(&start,NULL);
sort(nums,nums+NUMNUM,compare); //单线程排序,快速排序
gettimeofday(&end,NULL);
//计算用时
long long startusec = start.tv_sec * 1000000 + start.tv_usec;
long long endusec = end.tv_sec * 1000000 + end.tv_usec;
double elapsed = (double)(endusec - startusec) / 1000000.0;
printf("sort took %.4f seconds\n", elapsed);
//将排序后的结果写入文件, 以便查看是否已经排好序
FILE *fp = fopen("save.txt", "w+");
for (unsigned long i = 0; i < NUMNUM; i++)
fprintf(fp, "%ld ", nums[i]);
}
三次排序用时如下:
sort took 3.2435 seconds
sort took 3.2221 seconds
sort took 3.2134 seconds
(附-主机配置: 双核四线程(Intel(R) Core(TM) i3-2350M CPU @ 2.30GHz))
多线程排序(使用屏障同步)
#define NTHR 8 /* 线程数 */
#define NUMNUM 8000000L /* 待排序数 */
#define TNUM (NUMNUM/NTHR) /* 每个线程分配到的需要排序的数 */
long nums[NUMNUM];
long snums[NUMNUM];
pthread_barrier_t b; //屏障
bool compare(long a, long b)
{
return a < b;
}
//排序线程
//对nums数组的从idx~idx+TNUM部分进行快速排序
void *workThread(void *arg)
{
long idx = (long)arg;
sort(&nums[idx],&nums[idx+TNUM],compare);
pthread_barrier_wait(&b);
pthread_exit(NULL);
}
//对已经排好序数组nums的NTHR部分进行合并
void merge()
{
long idx[NTHR]; //idx保存数组nums的NTHR部分的起始位置
for (long i = 0; i < NTHR; i++)
idx[i] = i * TNUM;
for (long sidx = 0; sidx < NUMNUM; sidx++)
{
long minidx;
long num = LONG_MAX;
//从NTHR部分的数组中查找出最小的一个, 将其index保存到idx[minidx]中
for (long i = 0; i < NTHR; i++)
{
//idx[i] < (i+1)*TNUM 确保是在一个部分之中,
//不会产生两个部分相互比较的情况
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()
{
srandom(time(NULL));
for (unsigned long i = 0; i < NUMNUM; i++)
nums[i] = random();
//创建NTHR个线程分别对数组相邻的NTHR部分进行排序
struct timeval start, end;
pthread_t tid;
gettimeofday(&start, NULL);
pthread_barrier_init(&b, NULL, NTHR+1);
for (unsigned long i = 0; i < NTHR; i++)
pthread_create(&tid, NULL,workThread, (void *)(i * TNUM));
pthread_barrier_wait(&b);
merge();
gettimeofday(&end, NULL);
//计算用时
long long startusec = start.tv_sec * 1000000 + start.tv_usec;
long long endusec = end.tv_sec * 1000000 + end.tv_usec;
double elapsed = (double)(endusec - startusec) / 1000000.0;
printf("sort took %.4f seconds\n", elapsed);
//将排序后的结果写入文件, 以便查看是否已经排好序
FILE *fp = fopen("save.txt", "w+");
for (unsigned long i = 0; i < NUMNUM; i++)
fprintf(fp, "%ld ", snums[i]);
}
八线程排序:
sort took 1.5556 seconds
sort took 1.5676 seconds
sort took 1.5719 seconds
四线程排序:
sort took 1.4132 seconds
sort took 1.4315 seconds
sort took 1.4738 seconds
二线程排序:
sort took 2.0581 seconds
sort took 2.2358 seconds
sort took 1.7775 seconds
(附-主机配置: 双核四线程(Intel(R) Core(TM) i3-2350M CPU @ 2.30GHz))
总结: 可以看到尽管在分别进行排序之后还要有合并(merge)这一步,多线程排序(计算密集型任务)还是要优于单线程排序(在CPU为多核的情况下),而且在CPU为四线程下,使用四个线程对数组进行排序,所耗费时间是最少的!