多线程堆排序算法C语言实现
代码主要实现对八十万个长整型数据的排序;利用8个线程实现,每个线程负责十万个数,数据由rand()函数产生。
代码如下:
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<time.h>
#include<sys/time.h>
#include<limits.h>
#include<pthread.h>
#define NTHR 8
#define NUMNUM 80
#define TNUM (NUMNUM/NTHR)
long nums[NUMNUM];
long snums[NUMNUM];
pthread_barrier_t b;
struct heap{
long array[TNUM+1];
long heapSize;
};
typedef struct heap Heap;
typedef long index;
int siftdown(Heap *heap,index i){
index parent,largchild;
long siftkey;
bool spotfound;
siftkey=heap->array[i];
parent=i;
spotfound=false;
while(2*parent<=heap->heapSize && !spotfound){
if(2*parent<heap->heapSize &&
heap->array[2*parent]<heap->array[2*parent+1]){
largchild=2*parent+1;
}else{
largchild=2*parent;
}
if(siftkey<heap->array[largchild]){
heap->array[parent]=heap->array[largchild];
parent=largchild;
}else
spotfound=true;
}
heap->array[parent]=siftkey;
return 0;
}
int root(Heap *heap){
long keyout;
keyout=heap->array[1];
heap->array[1]=heap->array[heap->heapSize];
heap->heapSize=heap->heapSize-1;
siftdown(heap,1);
return keyout;
}
int removekeys(long n,Heap *heap,long *array){
index i;
for(i=n;i>=1;i--){
heap->array[i]=root(heap);
}
}
int makeHeap(long n,Heap *heap){
index i;
heap->heapSize=n;
for(i=n/2;i>=1;i--)
siftdown(heap,i);
}
int checkResult(Heap *heap){
for(long i=1;i<TNUM+1;i++){
if(heap->array[i]-heap->array[i-1]<0){
printf("fail to sort\n");
exit(1);
}
}
printf("sort succeed!\n");
return 0;
}
int printResult(Heap *heap){
for(long i=1;i<TNUM+1;i++){
if(i%10==0)
printf("\n");
printf("%ld ",heap->array[i]);
}
printf("\n");
return 0;
}
int heapSort(long *array,long heapSize){
int err=0;
Heap heap;
heap.array[0]=0;
for(long i=1;i<heapSize+1;i++)
heap.array[i]=array[i-1];
makeHeap(heapSize,&heap);
removekeys(heapSize,&heap,heap.array);
//printResult(heap);
err=checkResult(&heap);
if(err!=0)
exit(1);
//printf("succeed!\n");
for(long i=1;i<heapSize+1;i++){
array[i-1]=heap.array[i];
}
return err;
}
void * thr_fn(void *arg){
long idx=(long)arg;
int err=0;
err=heapSort(&nums[idx],TNUM);
if(err!=0){
printf("fail to sort");
exit(1);
}
printf("sort finish!\n");
pthread_barrier_wait(&b);
return ((void *)0);
}
int merge(){
long idx[NTHR];
long i,minidx,sidx,num;
for(i=0;i<NTHR;i++){
idx[i]=i*TNUM;
}
for(sidx=0;sidx<NUMNUM;sidx++){
num=INT_MAX;
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(){
unsigned long i;
struct timeval start,end;
long long startusec, endusec;
double elapsed;
int err;
pthread_t tid;
srandom(1);
for(i=0;i<NUMNUM;i++){
nums[i]=rand()%100+1;
}
gettimeofday(&start,NULL);
pthread_barrier_init(&b,NULL,NTHR+1);
for(i=0;i<NTHR;i++){
err=pthread_create(&tid,NULL,thr_fn,(void *)(i*TNUM));
if(err!=0)
printf("can't create thread\n");
}
pthread_barrier_wait(&b);
merge();
gettimeofday(&end,NULL);
startusec=start.tv_sec*1000000+start.tv_usec;
endusec=end.tv_sec*1000000+end.tv_usec;
elapsed=(double)(endusec-startusec)/1000000.0;
printf("sort took %.4f seconds\n",elapsed);
for(i=0;i<NUMNUM;i++)
printf("%ld\n",snums[i]);
exit(0);
}
在主要介绍pthread_barrier_
函数:
- 使用屏障需要初始化,
pthread_barrier_init
函数在初始化时一般把等待线程数量设置为NTHER+1(申请的线程数量加一),其实是把主线程包含在内了。
这样做的原因是:如果只同步申请的子线程,那么子线程完成只时不知道主线程是否完成;因此在线程处理函数中每个子线程完成运算之后用pthread_barrier_wait
函数等待,主线程中也等待,这样可以保证,所有的线程都执行到屏障处之后,一起进行下一步运行。