一、 实验内容或题目:
以多线程编程的方式完成:
1)随机生成一个数组,求其平均值
2)随机生成一个数组,求其最大值
3)随机生成一个数组,求其最小值
二、 实验目的与要求:
上传的multi-thread.c已经以单线程的方式完成了上述工作。
请将之更改成多线程完成工作的方式,在数组长度较大的情况下,并观察单线程与多线程方式之间的时间对比。
三、 实验步骤:
需要使用的api:
_beginthread, CreateThread, WaitForSingleObject
四、 实验结果:
单进程
多进程(由于__declspec(thread)的限制,只能将generateNumbers()函数放入方法中,达到线程局部变量的效果)
五、 总结:
根据多次实验的结果,多线程所用的时间明显要小于单线程,多线程可同时运行多个程序,一定程度上提高了响应速度,更能充分利用CPU。
拓展思考
实验中使用了__declspec(thread)来标识pNumbers指针变量,请回答:
1)此标识符的作用是什么?
2)如果没有此标识符来修饰pNumbers指针变量,程序能运行正确吗?
答:
1) 声明一个线程局部变量,可以为每个线程生成一副本,使该变量不能被多个线程共享访问,各个线程使用各自的这个变量,互不影响。 为什么要使用这个声明符号,因为“C/C++运行库是在多线程程序出现的很多年前设计的,所以运行库中的很多函数都是不支持多线程的,所以在多线程的环境中使用运行库中的函数会发生各种各样的错误与缺陷,C/C++运行库的解决方案就是使用TLS”(TLS:Thread local Storage,线程局部存储区)。
2) 在单线程中有无都可运行,而在多线程中,添加了__declspec(thread)反而无法运行,查询了一些资料,可能是因为__declspec(thread)变量是在静态链接的时候确定存储位置的,如果动态加载,这些变量实际上都是空,地址可能是0或者任何数值。
我觉得,既然__declspec(thread)是用来声明线程局部变量的,因该把generateNumbers(cardinality)放在每个子进程调用的方法中,这样的化程序可以正确运行
直接将示例代码改成多线程版,数组依然用__declspec(thread)声明,程序无法运行,原因可能是这个。
源码
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>
#include <math.h>
#include <time.h>
#define Thread __declspec( thread )
Thread int* pNumbers = NULL;
void generateNumbers(unsigned int cardinality) {
pNumbers = (int*)malloc(cardinality * sizeof(unsigned int));
assert(pNumbers);
unsigned int iter;
srand((unsigned int)time(NULL));
for (iter = 0; iter < cardinality; iter++) {
pNumbers[iter] = rand();
}
return;
}
void getMax(unsigned int cardinality) {
unsigned int iter;
unsigned int max = 0;
for (iter = 0; iter < cardinality; iter++) {
if (pNumbers[iter] > max) {
max = pNumbers[iter];
}
}
printf("Max is %d\n", max);
}
void getMin(unsigned int cardinality) {
unsigned int iter;
unsigned int min = UINT_MAX;
for (iter = 0; iter < cardinality; iter++) {
if (pNumbers[iter] < min) {
min = pNumbers[iter];
}
}
printf("Min is %d\n", min);
}
void getAvg(unsigned int cardinality) {
unsigned int iter;
unsigned long long sum = 0;
for (iter = 0; iter < cardinality; iter++) {
sum += pNumbers[iter];
}
printf("Average is %f\n", (float)(sum / cardinality));
}
unsigned int TimeOfMin, TimeOfMax, TimeOfAverage;
int main(int argc, char* argv[]) {
if (argc < 2) {
printf("input the cardinality of numbers to be processed.\n");
return -1;
}
int cardinality = atoi(argv[1]);
if (cardinality <= 0) {
printf("please input a positive number as cardinality.\n");
return -1;
}
else if (cardinality > 99999999) {
printf("cardinality is too big to process.\n");
return -1;
}
clock_t start = clock();
{
printf("creating %d numbers randomly\n", cardinality);
generateNumbers(cardinality);
getMax(cardinality);
printf("creating %d numbers randomly\n", cardinality);
generateNumbers(cardinality);
getMin(cardinality);
printf("creating %d numbers randomly\n", cardinality);
generateNumbers(cardinality);
getAvg(cardinality);
}
clock_t finish = clock();
double duration = (double)(finish - start);
/
printf("Time collapsed: %f ms\n", duration);
free(pNumbers);
return 0;
}
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>
#include <math.h>
#include <time.h>
#define Thread __declspec( thread )
Thread int* pNumbers = NULL;
void generateNumbers(unsigned int cardinality) {
pNumbers = (int*)malloc(cardinality * sizeof(unsigned int));
assert(pNumbers);
unsigned int iter;
srand((unsigned int)time(NULL));
for (iter = 0; iter < cardinality; iter++) {
pNumbers[iter] = rand();
}
return;
}
void getMax(unsigned int cardinality) {
unsigned int iter;
unsigned int max = 0;
generateNumbers(cardinality);
for (iter = 0; iter < cardinality; iter++) {
if (pNumbers[iter] > max) {
max = pNumbers[iter];
}
}
printf("Max is %d\n", max);
}
//当函数不允许接受参数时,必须使用void限定
void getMin(void* lpVoid) {
unsigned int iter;
unsigned int min = UINT_MAX;
//获得cardinality
unsigned int cardinality = (int)lpVoid;
generateNumbers(cardinality);
for (iter = 0; iter < cardinality; iter++) {
if (pNumbers[iter] < min) {
min = pNumbers[iter];
}
}
printf("Min is %d\n", min);
}
void getAvg(void* lpVoid) {
unsigned int iter;
unsigned long long sum = 0;
unsigned int cardinality = (int)lpVoid;
generateNumbers(cardinality);
for (iter = 0; iter < cardinality; iter++) {
sum += pNumbers[iter];
}
printf("Average is %f\n", (float)(sum / cardinality));
}
unsigned int TimeOfMin, TimeOfMax, TimeOfAverage;
int main(int argc, char* argv[]) {
HANDLE hThread1, hThread2;
if (argc < 2) {
printf("input the cardinality of numbers to be processed.\n");
return -1;
}
int cardinality = atoi(argv[1]);
if (cardinality <= 0) {
printf("please input a positive number as cardinality.\n");
return -1;
}
else if (cardinality > 99999999) {
printf("cardinality is too big to process.\n");
return -1;
}
clock_t start = clock();
{
//主线程
printf("creating %d numbers randomly\n", cardinality);
getMax(cardinality);
//子线程1
printf("creating %d numbers randomly\n", cardinality);
HANDLE hThread1 = (HANDLE)_beginthread(getMin, 0, (void*)cardinality);
WaitForSingleObject(hThread1, INFINITE);
//子线程2
printf("creating %d numbers randomly\n", cardinality);
HANDLE hThread2 = (HANDLE)_beginthread(getAvg, 0, (void*)cardinality);
WaitForSingleObject(hThread2, INFINITE);
}
clock_t finish = clock();
double duration = (double)(finish - start);
printf("Time collapsed: %f ms\n", duration);
free(pNumbers);
_endthread();
return 0;
}