利用多线程计算元素数组的和
CS:APP有一章节讲的是多线程,里面有一个例子讲的是利用多线程可重入地计算数组元素的和。因为加法满足交换率,多线程计算数组元素的和再相加数学上是正确的。
首先一开始想写一个共享变量sum,所有线程都往sum上加,后来发现这样必须加锁,不然存在很严重的线程不安全问题,但是256个锁…画面太美不敢看,所以干脆写成可重入的函数了。
以下为代码:为了方便测量性能,我们令每一次加法内部做无用功浪费一点时间。所以编译起来有两个问题,一是不能开-O1,-O2,因为会把无用代码优化调,所以开-O0,二是一定要加-pthread。因为 pthread.h不是Linux默认静态库。
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
#include<time.h>
#define LEN 2560000
#define N 256
#define TIMES 100
#define WASTE 100
int data[LEN];
int sum[N];
int ans;
void init()
{
ans=0;
for (int i=0;i<N;i++)
sum[i]=0;
for (int i=0;i<LEN;i++)
data[i]=1;
return;
}
void dosomething()
{
for (int i=0;i<WASTE;i++);
return;
}
void* thread(void* vargp)
{
int k=((int*) vargp)[0];
int n=((int*) vargp)[1];
for (int i=k*LEN/n;i<(k+1)*LEN/n;i++)
for (int j=0;j<TIMES;j++)
{
sum[k]+=data[i];
dosomething();
}
return NULL;
}
int main()
{
int* ptr;
int var[N][2];
int cpe,cpe1;
pthread_t tid[N];
time_t t1,t2;
for (int n=1;n<=N;n=n*2)
{
time(&t1);
init();
for (int i=0;i<n;i++)
{
var[i][0]=i;
var[i][1]=n;
pthread_create(&tid[i],NULL,thread,(void*)var[i]);
}
for (int i=0;i<n;i++)
pthread_join(tid[i],NULL);
for (int i=0;i<n;i++)
ans+=sum[i];
if (ans!=LEN*TIMES)
{
printf("Wrong Answer!\n");
printf("ans=%d(but it should be %d!)\n",ans,LEN*TIMES);
exit(1);
}
time(&t2);
cpe=TIMES*LEN/((int)(t2-t1))/1000;
if (n==1)
cpe1=cpe;
printf("%3d threads:time=%2d,CPE=%dK,acc rate=%.3f\n",
n,(int)(t2-t1),cpe,((float)cpe)/cpe1);
}
exit(0);
}
测试结果(CPE是一个相对参数,没有单位,大致指的是每一个元素处理的时间代价)
zzy@zzy-lenovo-g50-80:~/zzy/project/ICS/pthread$ ./psum
1 threads:time=64,CPE=4000K,acc rate=1.000
2 threads:time=34,CPE=7529K,acc rate=1.882
4 threads:time=29,CPE=8827K,acc rate=2.207
8 threads:time=27,CPE=9481K,acc rate=2.370
16 threads:time=27,CPE=9481K,acc rate=2.370
32 threads:time=27,CPE=9481K,acc rate=2.370
64 threads:time=26,CPE=9846K,acc rate=2.461
128 threads:time=27,CPE=9481K,acc rate=2.370
256 threads:time=26,CPE=9846K,acc rate=2.461
我们可以发现线程多于4个时候acc rate不再上升,也就是说很有可能zzy-lenovo-g50-80是一台四核的计算机。我们去网页上查了一查,发现是双核心四线程电脑,也就是说有超线程技术,所以可以同时处理四个线程,但是处理四线程因为超线程了,所以比双线程快不了多少,所以是双核心四线程计算机,与测量结果吻合。所以这个代码不仅可以求数组元素的和,还可以用来测量计算机的线程数。