关于多线程我总觉得是个比较难的东西,难在几点,比如线程的同步互斥等,还有实际编写代码时遇到的线程的调试问题,这些都是造成多线程比较难的原因,不过没有办法,还是需要面对,学习顺便做个记录和分析:
首先是源代码,如下(不同的问题需要自己修改源代码),程序最初的目的是加快x的运算速度,所以最初是采用的两个线程的形式,后来经过改进和分析即产生如下的源码原型。只作为分析用。
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
__int64 x=0;
__int64 y=0;
__int64 z=0;
__int64 q=0;
#define MAX 10000000000
DWORD WINAPI ThreadFunc1(LPVOID);
DWORD WINAPI ThreadFunc2(LPVOID);
DWORD WINAPI ThreadFunc3(LPVOID);
DWORD WINAPI ThreadFunc4(LPVOID);
//目地是并行计算x的大小,让他很快的到最大的值,这样的话没有进行并行计算。
int main()
{
HANDLE hThrd[2];
DWORD threadId[2];
// HANDLE hThrd[4];
// DWORD threadId[4];
DWORD start_time = GetTickCount(); //获取系统时钟
hThrd[0] = CreateThread(NULL,
0,
ThreadFunc1,
(LPVOID)0,
0,
&threadId[0]);
/* hThrd[1] = CreateThread(NULL,
0,
ThreadFunc2,
(LPVOID)0,
0,
&threadId[1]);
*/
/* hThrd[2] = CreateThread(NULL,
0,
ThreadFunc3,
(LPVOID)0,
0,
&threadId[2]);
hThrd[3] = CreateThread(NULL,
0,
ThreadFunc4,
(LPVOID)0,
0,
&threadId[3]);
*/
// WaitForMultipleObjects(2,hThrd,TRUE,INFINITE);
// Sleep(1000);
// WaitForMultipleObjects(4,hThrd,TRUE,INFINITE);
WaitForSingleObject(hThrd[0],INFINITE);
CloseHandle(hThrd[0]);
CloseHandle(hThrd[1]);
// x= x+y;
// x= x+y+z+q;
DWORD end_time = GetTickCount();
printf("time :%d\n",end_time-start_time);
printf("x: %I64d\n",x);
return EXIT_SUCCESS;
}
DWORD WINAPI ThreadFunc1(LPVOID)
{
while(x<MAX)
{
x++;
// printf("thread1: %d\n",x);
// Sleep(10);
}
return 0;
}
DWORD WINAPI ThreadFunc2(LPVOID)
{
while(y<MAX/2)
// while(x<10000000)
{
y++;
// x++;
// printf("thread2: %d\n",x);
// Sleep(10);
}
return 0;
}
DWORD WINAPI ThreadFunc3(LPVOID)
{
// while(x<10000000)
while(z<MAX/4)
{
z++;
// x++;
// printf("thread3: %d\n",x);
// Sleep(10);
}
return 0;
}
DWORD WINAPI ThreadFunc4(LPVOID)
{
// while(x<10000000)
while(q<MAX/4)
{
q++;
// x++;
// printf("thread4: %d\n",x);
// Sleep(10);
}
return 0;
}
下面针对不同的问题产生的不同结结果,首先是采用多线程直接对x自加,单个线程的情况(time :31 x: 10000000),然后是两个线程(time :16 x: 10000000),(time :31 x: 10000000)每次运行的时间可能不一样,并且差别较大,更多的时候时间为31,32左右,然后是四个线程,四个线程时间反而比两个线程运行的时间长一些(time :47 x: 10000000),有时是(time :31 x: 10000000),也不是稳定的,关于执行时间为什么会长一些后面做解释,这里为什么两个线程,四个线程基本上没有加快速度,直接对x进行自加的操作,真正意义上并没有做到并行计算x。并行计算需要将x进行分割,然后启用多个线程同时运行,至于多少个线程就需要看实际的情况,
将数据分割后,采用两个线程时,结果为(time :16 x: 10000000),时间一般是15,16趋于稳定,四个线程时间是否会编程4左后呢?,我猜想是的,但是结果确不是的,和两个线程的情况基本相同,这里有一点不懂,为什么时间基本上没有缩短,(我猜想可能是我的电脑为双核的原因)其实是真的不明白!!!
于是我把数据变大到10000000000,单个线程的结果为(time :31699 x: 10000000000),两个线程的时间为(time :24570 x: 10000000000),四个线程的时间为
(time :23759 x: 10000000000),这里从1个到2个到4个线程基本上时间没有很明显的呈现两倍的趋势,主要还有一个原因就是,这几个线程都属于同一个进程,他们共享所有的内存,当线程同时运行时,会发生context switch(我称为设备文转换),而每次的context switch都会话费一点时间,也就是说"两个线程同时计算x比一个线程计算x两次的时间要长一些"当数据比较小时,转换的次数相对比较少,可以忽略,但是当数据比较大,就不能忽略,也就出现了后面的结果的时间分布情况。
总结:1 真正的数据并发需要对数据进行分布式的切割计算
2 当数据比较大时,用多少个进程,需要考虑context switch