提示:本文的所有代码由C语言实现,经过测试,C++的多线程操作也会遇到同样的问题。多线程库用的是pthread.h,操作系统是win10。windows下的pthread.h安装,可以参考下这篇文章:vs2017如何配置pthread环境
前言
最近因为工作需要,调研了一下C语言的多线程使用。在测试常用功能的时候遇到这么一个诡异的问题,通过结构体获取返回值的时候,多线程操作变慢了。经过一天的努力,最终解决了这个问题。以下是对该问题的记录。
一、多线程代码
1.带有返回值的多线程代码
下面代码包括生成一个5行1000万列的随机数组,然后分别使用多线程的和单线程的方法对每一行进行求和。其中多线程的参数是一个结构体,包括要求和的数组和一个sum返回值。
#include <stdio.h>
#include <time.h>
#include <pthread.h>
//定义随机数组的行和列
#define ROW 5
#define COL 10000000
//获得随机数组
int ** getRandom()
{
printf("生成%dX%d的随机数组\n", ROW, COL);
int **r;
r = (int **)malloc(ROW * sizeof(int));
for (int i = 0; i < ROW; i++) {
r[i] = (int *)malloc(COL * sizeof(int));
}
srand((unsigned)time(NULL));
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; ++j)
{
r[i][j] = rand();
}
}
printf("随机数组生成完毕\n\n");
return r;
}
//定义传入线程的结构体
typedef struct TagValue
{
int *arr;
long long sum;
} Tag;
//子线程调用求和方法
void* threadSum(void *d) {
Tag *v = (Tag*)d;
int *arr = v->arr;
for (int i = 0; i < COL; i++) {
v->sum += *(arr + i);
}
}
//多线程主方法
void testThreadTime(int **r) {
//计算多线程运行时间
clock_t start, end;
//传入参数结构体
Tag res[ROW];
//线程id号
pthread_t ths[ROW];
//记时开始
start = clock();
for (int i = 0; i < ROW; i++) {
res[i].arr = r[i];
res[i].sum = 0;
//开启子线程
int ret_thrd1 = pthread_create(&ths[i], NULL, (void *)&threadSum, (void *)&res[i]);
// 线程创建成功,返回0,失败返回失败号
if (ret_thrd1 != 0) {
printf("子线程%d创建失败\n",i);
}else {
printf("子线程%d创建成功\n",i);
}
}
//增加join函数,使主线程等待子线程都结束
for (int i = 0; i < ROW; i++) {
pthread_join(ths[i], NULL);
}
//打印返回值
printf("多线程的执行结果是:\n");
for (int i = 0; i < ROW; i++) {
printf("%lld\n", res[i].sum);
}
printf("主线程执行完毕\n");
//计时结束
end = clock();
printf("Time Used: %f\n\n", difftime(end, start));
}
//非多线程对照方法
void testNoThreadTime(int **r) {
clock_t start, end;
//int **r = getRandom();
long long res[ROW];
memset(res, 0, ROW * sizeof(long long));
start = clock();
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COL; j++) {
res[i] += r[i][j];
}
}
end = clock();
printf("对照组执行结果是:\n");
for (int i = 0; i < ROW; i++) {
printf("%lld\n", res[i]);
}
printf("Time Used: %f\n\n", difftime(end, start));
}
int main() {
int **r = getRandom();
testThreadTime(r);
testNoThreadTime(r);
getchar();
return 0;
}
2.结果展示
可见多线程不但没有减少计算时间,反而增加了很多。
二、问题修复
1.修改子线程调用方法
出现问题是threadSum函数里的这句代码v->sum += *(arr + i),这句代码对主线程里声明的地址内容进行了大量的修改操作。按照下面方式修改,声明临时变量sum,求和在临时变量sum中进行,只需进行简单的修改,多线程变慢的问题就解决了
void* threadSum(void *d) {
Tag *v = (Tag*)d;
int *arr =v->arr;
long long sum = 0;
for (int i = 0; i < COL; i++) {
sum+=*(arr + i);
}
v->sum = sum;
}
2.结果展示
修改之后,多线程已经可以正常提升计算效率了。
总结
在C/C++的多线程使用过程中,一定要注意在子线程中对传入地址的写操作。频繁的跨线程写操作,会带来效率的大幅降低。