我的多线程C程序运行以下例程:
#define NUM_LOOP 500000000
long long sum = 0;
void* add_offset(void *n){
int offset = *(int*)n;
for(int i = 0; i<NUM_LOOP; i++) sum += offset;
pthread_exit(NULL);
}
当然,应该通过获取锁来更新总和,但是在此之前,我对这个简单程序的运行时间有疑问.
当主要功能是(单线程)时:
int main(void){
pthread_t tid1;
int offset1 = 1;
pthread_create(&tid1,NULL,add_offset,&offset1);
pthread_join(tid1,NULL);
printf("sum = %lld\n",sum);
return 0;
}
输出和运行时间为:
sum = 500000000
real 0m0.686s
user 0m0.680s
sys 0m0.000s
当主要功能是(多线程顺序)时:
int main(void){
pthread_t tid1;
int offset1 = 1;
pthread_create(&tid1,NULL,add_offset,&offset1);
pthread_join(tid1,NULL);
pthread_t tid2;
int offset2 = -1;
pthread_create(&tid2,NULL,add_offset,&offset2);
pthread_join(tid2,NULL);
printf("sum = %lld\n",sum);
return 0;
}
输出和运行时间为:
sum = 0
real 0m1.362s
user 0m1.356s
sys 0m0.000s
到目前为止,程序已按预期运行.但是当主要功能是(多线程并发)时:
int main(void){
pthread_t tid1;
int offset1 = 1;
pthread_create(&tid1,NULL,add_offset,&offset1);
pthread_t tid2;
int offset2 = -1;
pthread_create(&tid2,NULL,add_offset,&offset2);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
printf("sum = %lld\n",sum);
return 0;
}
输出和运行时间为:
sum = 166845932
real 0m2.087s
user 0m3.876s
sys 0m0.004s
由于缺少同步,sum的错误值不是问题,而是运行时间.并发执行的实际运行时间远远超过顺序执行的时间.它与多核CPU中并发执行的预期相反.
请在这里说明可能是什么问题.
解决方法:
如果多个线程访问相同的共享状态(至少在x86上),这并非罕见.通常称为cache line ping-pong:
每当一个内核想要更新该变量的值时,它首先必须从另一内核获取缓存行的“所有权”(锁定写入的缓存行),这需要一些时间.然后另一个核心要回缓存行…
因此,即使没有同步原语,与顺序情况相比,您仍要付出可观的开销.