pthread其实也可以当作C/C++的一个库,所有的函数和数据类型都在
gcc filename.c -lpthread
pthread就是能让C程序的进程在运行时可以分叉为多个线程执行.例如main函数就可以分叉为下面的两个线程.
很容易想到,pthread使用分为三个部分:分叉,运行,合并.所有的过程都在下面的程序中给出.
#include
#include
#include
int thread_count = 4;
void *Hello(void *rank);
int main()
{
// 循环变量
long thread;
// 进程的标号,数组
pthread_t *thread_handles;
// 分配空间
thread_handles =(pthread_t *)malloc(thread_count * sizeof(pthread_t));
// 绑定线程,开始分叉
for (thread = 0; thread < thread_count; ++thread)
// 将线程hello,和给hello的参数绑定到线程上
// 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;
}
void *Hello(void *rank)
{
long my_rank = (long)rank;
printf("Hello from thread %ld of %d\n", my_rank, thread_count);
return NULL;
}
使用pthread_create函数开始分叉.pthread_create函数的第一个参数就是线程的标号,第二个参数暂时用不到,给NULL就可以了;第三个参数是在该线程执行的函数,函数的签名必须返回空指针,传递空指针的参数;第四个参数传递参数,因此也必须转成空指针.
运行线程的过程就是运行4个Hello函数的过程
使用pthread_join合并,结束线程.pthread_join第一个参数是线程的标号;第二个参数暂时不用,给NULL.
目的:
测试计算 1 0 7 10^7 107维的向量加法使用AVX和普通for循环的速度差异
实验测试的数据类型为双精度浮点数double类型,两个向量由 1 0 7 10^7 107个double类型数据组成.
废话少说,上代码.
代码:
#include
#include
#include
#include
// 定义向量的长度
#define __VEC_LENGTH__ 10000000
// 线程数量
int thread_count = 4;
// 第一个向量
double arr1[__VEC_LENGTH__];
// 第二个向量
double arr2[__VEC_LENGTH__];
// 计算加法的结果
double result[__VEC_LENGTH__];
// 每个线程执行的函数
void *sum_vec(void *rank);
int main()
{
long thread;
pthread_t *thread_handles;
int i;
srand(time(NULL));
thread_handles =(pthread_t *)malloc(thread_count * sizeof(pthread_t));
for(i = 0; i < __VEC_LENGTH__; ++i)//随机初始化函数
{
arr1[i] = rand() / 9999;
arr2[i] = rand() / 9999;
}
struct timeval tv1, tv2;
gettimeofday(&tv1, NULL);
// 绑定线程,开始分叉
for (thread = 0; thread < thread_count; ++thread)
// 将线程hello,和给hello的参数绑定到线程上
pthread_create(&thread_handles[thread], NULL,
sum_vec, (void *)thread);
// 结束线程
for (thread = 0; thread < thread_count; ++thread)
pthread_join(thread_handles[thread], NULL);
gettimeofday(&tv2, NULL);
// 输出高维加法执行时间
printf("Spliting the date to 4 pieces",
" takes %ld us\n",
(tv2.tv_sec - tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec);
printf("The first three elements of result is %lf %lf %lf\n",
result[0], result[1], result[2]);
free(thread_handles);
return 0;
}
以上是main函数和每个线程执行的函数签名,具体相加的函数不是重点,放在下面.普通数组实现加法太过简单,可以参考这篇文章或者这个代码:
void *sum_vec(void *rank)
{
long my_rank = (long)rank;
// 每个线程都计算 __VEC_LENGTH__ / thread_count 个元素相加
int i;
int my_work = __VEC_LENGTH__ / thread_count;
int my_first = my_rank * my_work;
int my_last = (my_rank + 1) * my_work;
for (i = my_first; i < my_last; ++i)
{
result[i] = arr1[i] + arr2[i];
}
return NULL;
}
1 | 2 | 3 | 4 | 5 | 均值 | |
---|---|---|---|---|---|---|
多线程加法(单位um) | 63294 | 43699 | 42220 | 47738 | 43216 | 48033.4 |
单线程加法(单位um) | 81926 | 103015 | 110047 | 122131 | 90447 | 101513.2 |
实验测了5次4线程的情况得到加速比为2.11.
注:程序运行在Ryzen 5 3500U上
(1)多线程程序运行时间不可能随着线程的增加一直减少,因此这里给出1个线程到11个线程的运行时间图(单位为um):
(2)程序使用了两种不同的方式先计算向量加法,线程数为4时,理论(根据Amdahl定律)上最大的加速比应该为4.但是实际运行的过程中,由于多线程程序有调用函数、分配内存等额外开销,因此加速比远远没有到达4.当然,也有可能是在编译的过程中,编译器对本来不是并行的代码做了优化,把简单的for循环变成并行执行的程序,从而导致加速比低于4.