Pthreads学习笔记1 Pthreads用共享内存模型进行并行编程。一般地,程序会启动一个主线程,执行main函数中的代码,然后由主线程启动其他的线程。
Pthreads的hello world程序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <pthread.h> #include <stdio.h> #include <stdlib.h> int thread_count;void * Hello (void * rank) { long my_rank=(long )rank; printf ("Hello from thread %ld of %d\n" ,my_rank,thread_count); return NULL ; } int main (int argc,char ** argv) { if (argc!=2 )abort (); long thread; pthread_t * thread_handles; thread_count=strtol(argv[1 ],NULL ,10 ); thread_handles=malloc (thread_count*sizeof (pthread_t )); for (thread=0 ;thread<thread_count;thread++)pthread_create(&thread_handles[thread],NULL ,Hello,(void *)thread); printf ("Hello from the main thread\n" ); for (thread=0 ;thread<thread_count;thread++)pthread_join(thread_handles[thread],NULL ); free (thread_handles); return 0 ; }
这个程序里值得注意的是第16行至第22行。 第16行定义了一个pthread_t类型的指针。pthread_t用来存储线程的专有信息,可以作为线程的唯一标识,它的数据是由系统进行绑定的,用户无法访问。 在第17行,我们用命令行参数来得到线程数量。 18行给thread_handles分配了 thread_cound 个 pthread_t 对象的地址空间。 19行调用pthread_create()函数,它的原型为:
1 int pthread_create (pthread_t * thread_p,const pthread_attr_t * attr_p,void * (*start_routine)(void *),void * arg_p) ;
第一个参数是一个指向pthread_t对象的指针,且必须提前为它分配地址,以便pthread_create修改它指向的内容。第二个参数一般就是NULL,不用管。
第三个参数是一个指针,指向一个函数,这个函数只有一个参数,是一个指向void类型的指针,返回值也是一个指向void类型的指针。
第四个参数是一个指向void类型的指针,用它来给第三个参数指向的函数提供参数。
通过pthread_create()函数我们创建了一个线程,它要做的就是执行第三个参数指向的函数。在第19行里,我们给它的第三个参数是Hello函数,第四个参数是(void*)thread。
在这里,thread变量可以用来标志线程号,把它转化为(void*)指针是为了跟Hello函数的参数列表匹配。此后,在Hello函数里,我们又把它转化为long类型,这样我们就可以得到这个线程的线程号。
第21行调用了pthread_join()函数,顾名思义,它用来等待那个线程的结束。
第22行用来free掉thread_handles数组。
运行的结果如下: 注意,main函数执行第20行时,其他线程已经启动,所以输出的顺序是不确定的。
矩阵向量乘 用pthreads编写一个矩阵向量乘的程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <sys/time.h> int thread_count,n,m;double ** A,*x,*y;void * Pth_mat_vect (void * rank) { long my_rank=(long )rank; int i,j,local_m=m/thread_count; int my_first_row=my_rank*local_m,my_last_row=my_first_row+local_m; for (i=my_first_row;i<my_last_row;i++){ double tem=0.0 ,*A2=A[i]; for (j=0 ;j<n;j++){ tem+=A2[j]*x[j]; } y[i]=tem; } return NULL ; } int main (int argc,char ** argv) { freopen("out2.txt" ,"a" ,stdout ); if (argc!=4 )abort (); long thread; pthread_t * thread_handles; thread_count=strtol(argv[1 ],NULL ,10 ); m=strtol(argv[2 ],NULL ,10 ); n=strtol(argv[3 ],NULL ,10 ); A=(double **)malloc (m*sizeof (double *)); for (int i=0 ;i<m;i++)A[i]=(double *)malloc (n*sizeof (double )); x=(double *)malloc (n*sizeof (double )); y=(double *)malloc (m*sizeof (double )); for (int i=0 ;i<m;i++){ for (int j=0 ;j<n;j++){ A[i][j]=(double )rand()/RAND_MAX; } } for (int i=0 ;i<n;i++)x[i]=(double )rand()/RAND_MAX; struct timeval tv ,tv2 ; gettimeofday(&tv,NULL ); thread_handles=malloc (thread_count*sizeof (pthread_t )); for (thread=0 ;thread<thread_count;thread++)pthread_create(&thread_handles[thread],NULL ,Pth_mat_vect,(void *)thread); for (thread=0 ;thread<thread_count;thread++)pthread_join(thread_handles[thread],NULL ); gettimeofday(&tv2,NULL ); printf ("%d\n" ,tv2.tv_sec*1000000 + tv2.tv_usec - tv.tv_sec*1000000 - tv.tv_usec); free (thread_handles); for (int i=0 ;i<m;i++)free (A[i]); free (A),free (x),free (y); return 0 ; }
平均用时如下:(单位μs) |矩阵大小\线程数|1|2|4|5|8|10| |:-:|:-:|:-:|:-:|:-:|:-:|:-:| |200|337 |282| 378 |895 |698| 969 | |500|803 |562| 625 |543| 829 |956| |1000|2716| 2499 |961 |1349| 1048| 1389| |2000|15894 |5466 |2855 |3469 |2559| 2778| |5000|65230 |30717 |26828 |20336 |13326| 14294| |10000|294865| 133474| 65650 |77883 |50221| 53250|
加速比如下:
矩阵大小\线程数
1
2
4
5
8
10
200
1
1.19504
0.891534
0.376536
0.482808
0.347781
500
1
1.42883
1.2848
1.47882
0.968637
0.839958
1000
1
1.08683
2.82622
2.01334
2.5916
1.95536
2000
1
2.90779
5.56708
4.58172
6.21102
5.72138
5000
1
2.12358
2.43141
3.20761
4.89494
4.56345
10000
1
2.20916
4.49147
3.786
5.87135
5.53737
效率如下:
矩阵大小\线程数
1
2
4
5
8
10
200
1
0.59752
0.22288
0.075307
0.060351
0.034778
500
1
0.71441
0.3212
0.29576
0.12108
0.083996
1000
1
0.54342
0.70656
0.40267
0.32395
0.19554
2000
1
1.4539
1.3918
0.91634
0.77638
0.57214
5000
1
1.0618
0.60785
0.64152
0.61187
0.45635
10000
1
1.1046
1.1229
0.7572
0.73392
0.55374