windows程序设计(18):多线程程序设计

先得多说两句进程与线程的基本知识。不过自己不是学计算机的,看《操作系统》的感觉就跟看马哲差不多,全是原理性的内容,感觉很干涩,就勉强说几句吧。

进程是程序,数据以及进程控制块(PCB)组成的,它是资源分配的最小单位。为什么要提出线程的概念呢?因为进程是资源的拥有者,所以进程使用起来代价太大了,得创建,撤销,切换,而且进程间数据的交换必须使用特定的机制。这导致一个系统中同时存在的进程不宜过多。由此,提出了一个比进程更小的概念——线程。线程是资源调度的最小单位,占有的资源少,而且可以共享进程资源。这意味着多个线程可以共享数据等资源,这就避免了复杂的通信机制。总而言之,线程的速度比进程的快。

肤浅的理解就是这些吧。还是看程序。

程序的要求是这样的:

显示4个窗口。第一个窗口必须显示一系列的递增数,第二个必须显示一系列的递增质数,而第三个必须显示Fibonacci数列(Fibonacci数列以数字0和1开始,后头每一个数都是其前两个数的和-即0、1、1、2、3、5、8等等)。这三个窗口应该在数字达到窗口底部时或者进行滚动,或者自行清除窗口内容。第四个窗口必须显示任意半径的圆,而程序必须在按下一个Escape键时终止。

先看一个非多线程的版本:

/*---------------------------------------
   MULTI1.C -- Multitasking Demo
			(c) Charles Petzold, 1998
  ---------------------------------------*/

#include <windows.h>
#include <math.h>

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int cyChar ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
				PSTR szCmdLine, int iCmdShow)
{

	static TCHAR	szAppName[] = TEXT ("Multi1") ;
	HWND			hwnd ;
	MSG				msg ;
	WNDCLASS		wndclass ;
	
	wndclass.style			= CS_HREDRAW | CS_VREDRAW ;
	wndclass.lpfnWndProc	= WndProc ;
	wndclass.cbClsExtra		= 0 ;
	wndclass.cbWndExtra		= 0 ;
	wndclass.hInstance		= hInstance ;
	wndclass.hIcon			= LoadIcon (NULL, IDI_APPLICATION) ;
	wndclass.hCursor		= LoadCursor (NULL, IDC_ARROW) ;
	wndclass.hbrBackground	= (HBRUSH) GetStockObject (WHITE_BRUSH) ;
	wndclass.lpszMenuName	= NULL ;
	wndclass.lpszClassName	= szAppName ;
	
	if (!RegisterClass (&wndclass))
	{
		MessageBox (NULL, TEXT ("This program requires Windows NT!"),
				  szAppName, MB_ICONERROR) ;
		return 0 ;
	}
	
	hwnd = CreateWindow (szAppName, TEXT ("Multitasking Demo"),
					 WS_OVERLAPPEDWINDOW,
					 CW_USEDEFAULT, CW_USEDEFAULT,
					 CW_USEDEFAULT, CW_USEDEFAULT,
					 NULL, NULL, hInstance, NULL) ;
	
	ShowWindow (hwnd, iCmdShow) ;
	UpdateWindow (hwnd) ;
	
	while (GetMessage (&msg, NULL, 0, 0))
	{
		TranslateMessage (&msg) ;
		DispatchMessage (&msg) ;
	}
	return msg.wParam ;
}

//检查是否到达客户区的底部
int CheckBottom (HWND hwnd, int cyClient, int iLine)
{
	//如果行数*行宽+行宽>客户区的宽度
	if (iLine * cyChar + cyChar > cyClient)
	{
		InvalidateRect (hwnd, NULL, TRUE) ;
		UpdateWindow (hwnd) ;
		//将行宽置为0
		iLine = 0 ;
	}
	return iLine ;
}

//窗口1:展示递增的序列

LRESULT APIENTRY WndProc1 (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static int	iNum, iLine, cyClient ;
	HDC			hdc ;
	TCHAR		szBuffer[16] ;
	
	switch (message)
	{
	case WM_SIZE:
		cyClient = HIWORD (lParam) ;
		return 0 ;
		
	case WM_TIMER:
		if (iNum < 0)
			iNum = 0 ;
		
		iLine = CheckBottom (hwnd, cyClient, iLine) ;
		hdc = GetDC (hwnd) ;

		TextOut (hdc, 0, iLine * cyChar, szBuffer, 
			    wsprintf (szBuffer, TEXT ("%d"), iNum++)) ;

		ReleaseDC (hwnd, hdc) ;
		iLine++ ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}

//窗口2:显示递增的质数
//求素数的方法:对于N来说,不必用从2到N一1的所有素数去除,用小于等于√N(根号N)的所有素数去除就可以了
LRESULT APIENTRY WndProc2 (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static int	iNum = 1, iLine, cyClient ;
	HDC			hdc ;
	int			i, iSqrt ;
	TCHAR		szBuffer[16] ;
	
	switch (message)
	{
	case WM_SIZE:
		cyClient = HIWORD (lParam) ;
		return 0 ;
		
	case WM_TIMER:
		do   {
			if (++iNum < 0)
				iNum = 0 ;

			//获得该数的开方
			iSqrt = (int) sqrt ((double)iNum) ;
			
			//用小于这个平方根的数依次去试除
			for (i = 2 ; i <= iSqrt ; i++)
				if (iNum % i == 0)
					break ;
		}
		while (i <= iSqrt) ;
		
		iLine = CheckBottom (hwnd, cyClient, iLine) ;
		hdc = GetDC (hwnd) ;

		TextOut (hdc, 0, iLine * cyChar, szBuffer, 
			    wsprintf (szBuffer, TEXT ("%d"), iNum)) ;

		ReleaseDC (hwnd, hdc) ;
		iLine++ ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}


//窗口3:显示Fibonacci数列
LRESULT APIENTRY WndProc3 (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static int	iNum = 0, iNext = 1, iLine, cyClient ;
	HDC			hdc ;
	int			iTemp ;
	TCHAR		szBuffer[16] ;
	
	switch (message)
	{
	case WM_SIZE:
		//或得客户区的高度
		cyClient = HIWORD (lParam) ;
		return 0 ;
		
	case WM_TIMER:

		//如果初值有问题,重新设置初值
		if (iNum < 0)
		{
			iNum  = 0 ;
			iNext = 1 ;
		}
		
		//检测是否到达屏幕底端
		iLine = CheckBottom (hwnd, cyClient, iLine) ;
		hdc = GetDC (hwnd) ;

		TextOut (hdc, 0, iLine * cyChar, szBuffer, 
			    wsprintf (szBuffer, TEXT ("%d"), iNum)) ;

		ReleaseDC (hwnd, hdc) ;
		//F0=0,F1=1,Fn=F(n-1)+F(n-2)
		iTemp  = iNum ;
		iNum   = iNext ;
		iNext += iTemp ;
		iLine++ ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}

//窗口4:显示半径随机的圆

LRESULT APIENTRY WndProc4 (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static int	cxClient, cyClient ;
	HDC			hdc ;
	int			iDiameter ;
	
	switch (message)
	{
	case WM_SIZE:
		//或得客户区大小
		cxClient = LOWORD (lParam) ;
		cyClient = HIWORD (lParam) ;
		return 0 ;
		
	case WM_TIMER:

		InvalidateRect (hwnd, NULL, TRUE) ;
		UpdateWindow (hwnd) ;
		
		//确保直径最小为1,最大不会超过客户区的显示范围
		iDiameter = rand() % (max (1, min (cxClient, cyClient))) ;
		hdc = GetDC (hwnd) ;
		//画椭圆:就是设定外接矩形
		Ellipse (hdc, (cxClient - iDiameter) / 2,
				    (cyClient - iDiameter) / 2,
				    (cxClient + iDiameter) / 2,
				    (cyClient + iDiameter) / 2) ;
		
		ReleaseDC (hwnd, hdc) ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}

//主窗口程序:

LRESULT APIENTRY WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND		hwndChild[4] ;
	static TCHAR *	szChildClass[] = { TEXT ("Child1"), TEXT ("Child2"),
							    TEXT ("Child3"), TEXT ("Child4") } ;
	static WNDPROC	ChildProc[] = { WndProc1, WndProc2, WndProc3, WndProc4 } ;
	HINSTANCE		hInstance ;
	int				i, cxClient, cyClient ;
	WNDCLASS		wndclass ;
	
	switch (message)
	{
	case WM_CREATE:
		hInstance = (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE) ;
		//窗口的大部分特征相同
		wndclass.style			= CS_HREDRAW | CS_VREDRAW ;
		wndclass.cbClsExtra		= 0 ;
		wndclass.cbWndExtra		= 0 ;
		wndclass.hInstance		= hInstance ;
		wndclass.hIcon			= NULL ;
		wndclass.hCursor		= LoadCursor (NULL, IDC_ARROW) ;
		wndclass.hbrBackground	= (HBRUSH) GetStockObject (WHITE_BRUSH) ;
		wndclass.lpszMenuName	= NULL ;

		//每个窗口有自己独立的名字和回调函数
		for (i = 0 ; i < 4 ; i++)
		{
			wndclass.lpfnWndProc   = ChildProc[i] ;
			wndclass.lpszClassName = szChildClass[i] ;
			
			RegisterClass (&wndclass) ;
			
			hwndChild[i] = CreateWindow (szChildClass[i], NULL,
							WS_CHILDWINDOW | WS_BORDER | WS_VISIBLE,
							0, 0, 0, 0, 
							hwnd, (HMENU) i, hInstance, NULL) ;
		}
		
		cyChar = HIWORD (GetDialogBaseUnits ()) ;
		//整个程序是通过计时器驱动的
		SetTimer (hwnd, 1, 10, NULL) ;
		return 0 ;
		
	case WM_SIZE:
		cxClient = LOWORD (lParam) ;
		cyClient = HIWORD (lParam) ;
		//将每个子窗口移动到正确的位置
		for (i = 0 ; i < 4 ; i++)
			MoveWindow (hwndChild[i], (i % 2) * cxClient / 2,
								 (i > 1) * cyClient / 2,
					  cxClient / 2, cyClient / 2, TRUE) ;
		return 0 ;
		
	case WM_TIMER:
		//每到来一个时钟信号,给子窗口发送时钟信号
		for (i = 0 ; i < 4 ; i++)
			SendMessage (hwndChild[i], WM_TIMER, wParam, lParam) ;
		
		return 0 ;
		
	case WM_CHAR:
		//16进制1B即10进制27:ESC键的ASC码
		if (wParam == '\x1B')
			DestroyWindow (hwnd) ;
		
		return 0 ;
		
	case WM_DESTROY:
		KillTimer (hwnd, 1) ;
		PostQuitMessage (0) ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}


 

程序流程比较简单:

在主窗口的回调函数的WM_CREATE消息下,创建并注册4个子窗口,然后设置一个计时器;在WM_SIZE消息下将它们移动到正确的位置上;每当WM_TIMER到来,向4个子窗口发送时钟信号。对于每个子窗口,当接收到WM_TIMER消息时,完成自己工作。

再看一个多线程的版本:

/*---------------------------------------
   MULTI2.C -- Multitasking Demo
			(c) Charles Petzold, 1998
  ---------------------------------------*/

#include <windows.h>
#include <math.h>
#include <process.h>

typedef struct
{
	HWND hwnd ;
	int  cxClient ;
	int  cyClient ;
	int  cyChar ;
	BOOL bKill ;
}
PARAMS, *PPARAMS ;

LRESULT APIENTRY WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
				PSTR szCmdLine, int iCmdShow)
{

	static TCHAR	szAppName[] = TEXT ("Multi2") ;
	HWND			hwnd ;
	MSG				msg ;
	WNDCLASS		wndclass ;
	
	wndclass.style			= CS_HREDRAW | CS_VREDRAW ;
	wndclass.lpfnWndProc	= WndProc ;
	wndclass.cbClsExtra		= 0 ;
	wndclass.cbWndExtra		= 0 ;
	wndclass.hInstance		= hInstance ;
	wndclass.hIcon			= LoadIcon (NULL, IDI_APPLICATION) ;
	wndclass.hCursor		= LoadCursor (NULL, IDC_ARROW) ;
	wndclass.hbrBackground	= (HBRUSH) GetStockObject (WHITE_BRUSH) ;
	wndclass.lpszMenuName	= NULL ;
	wndclass.lpszClassName	= szAppName ;
	
	if (!RegisterClass (&wndclass))
	{
		MessageBox (NULL, TEXT ("This program requires Windows NT!"),
				  szAppName, MB_ICONERROR) ;
		return 0 ;
	}
	
	hwnd = CreateWindow (szAppName, TEXT ("Multitasking Demo"),
					 WS_OVERLAPPEDWINDOW,
					 CW_USEDEFAULT, CW_USEDEFAULT,
					 CW_USEDEFAULT, CW_USEDEFAULT,
					 NULL, NULL, hInstance, NULL) ;
	
	ShowWindow (hwnd, iCmdShow) ;
	UpdateWindow (hwnd) ;
	
	while (GetMessage (&msg, NULL, 0, 0))
	{
		TranslateMessage (&msg) ;
		DispatchMessage (&msg) ;
	}
	return msg.wParam ;
}

//检测显示是否到达客户区的底部
int CheckBottom (HWND hwnd, int cyClient, int cyChar, int iLine)
{
	if (iLine * cyChar + cyChar > cyClient)
	{
		InvalidateRect (hwnd, NULL, TRUE) ;
		UpdateWindow (hwnd) ;
		iLine = 0 ;
	}
	return iLine ;
}

//窗口1:展示递增的序列

void Thread1 (PVOID pvoid)
{
	HDC	hdc ;
	int	iNum = 0, iLine = 0 ;
	PPARAMS pparams ;
	TCHAR   szBuffer[16] ;
	
	pparams = (PPARAMS) pvoid ;
	
	while (!pparams->bKill)
	{
		if (iNum < 0)
			iNum = 0 ;
		
		iLine = CheckBottom (pparams->hwnd,   pparams->cyClient,
						 pparams->cyChar, iLine) ;

		hdc = GetDC (pparams->hwnd) ;
		
		TextOut (hdc, 0, iLine * pparams->cyChar, szBuffer, 
			    wsprintf (szBuffer, TEXT ("%d"), iNum++)) ;			
		
		ReleaseDC (pparams->hwnd, hdc) ;
		iLine++ ;
	}
	_endthread () ;
}

LRESULT APIENTRY WndProc1 (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static PARAMS params ;
	
	switch (message)
	{
	case WM_CREATE:
		params.hwnd = hwnd ;
		params.cyChar = HIWORD (GetDialogBaseUnits ()) ;
		_beginthread (Thread1, 0, ¶ms) ;
		return 0 ;
		
	case WM_SIZE:
		params.cyClient = HIWORD (lParam) ;
		return 0 ;
		
	case WM_DESTROY:
		params.bKill = TRUE ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}

//窗口2:显示递增的质数

void Thread2 (PVOID pvoid)
{
	HDC	hdc ;
	int	iNum = 1, iLine = 0, i, iSqrt ;
	PPARAMS pparams ;
	TCHAR   szBuffer[16] ;
	
	pparams = (PPARAMS) pvoid ;
	
	while (!pparams->bKill)
	{
		do
		{
			if (++iNum < 0)
				iNum = 0 ;
			
			iSqrt = (int) sqrt ((double)iNum) ;
			
			for (i = 2 ; i <= iSqrt ; i++)
				if (iNum % i == 0)
					break ;
		}
		while (i <= iSqrt) ;
		
		iLine = CheckBottom (pparams->hwnd,   pparams->cyClient,
						 pparams->cyChar, iLine) ;
		
		hdc = GetDC (pparams->hwnd) ;
		
		TextOut (hdc, 0, iLine * pparams->cyChar, szBuffer, 
			    wsprintf (szBuffer, TEXT ("%d"), iNum)) ;
		
		ReleaseDC (pparams->hwnd, hdc) ;
		iLine++ ;
	}
	_endthread () ;
}

LRESULT APIENTRY WndProc2 (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static PARAMS params ;
	
	switch (message)
	{
	case WM_CREATE:
		params.hwnd = hwnd ;
		params.cyChar = HIWORD (GetDialogBaseUnits ()) ;
		_beginthread (Thread2, 0, ¶ms) ;
		return 0 ;
		
	case WM_SIZE:
		params.cyClient = HIWORD (lParam) ;
		return 0 ;
		
	case WM_DESTROY:
		params.bKill = TRUE ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}

//窗口3:显示Fibonacci数列

void Thread3 (PVOID pvoid)
{
	HDC	hdc ;
	int	iNum = 0, iNext = 1, iLine = 0, iTemp ;
	PPARAMS pparams ;
	TCHAR   szBuffer[16] ;
	
	pparams = (PPARAMS) pvoid ;
	
	while (!pparams->bKill)
	{
		if (iNum < 0)
		{
			iNum  = 0 ;
			iNext = 1 ;
		}
		iLine = CheckBottom (pparams->hwnd,   pparams->cyClient,
						 pparams->cyChar, iLine) ;

		hdc = GetDC (pparams->hwnd) ;
		
		TextOut (hdc, 0, iLine * pparams->cyChar, szBuffer, 
			    wsprintf (szBuffer, TEXT ("%d"), iNum)) ;
		
		ReleaseDC (pparams->hwnd, hdc) ;
		iTemp  = iNum ;
		iNum   = iNext ;
		iNext += iTemp ;
		iLine++ ;
	}
	_endthread () ;
}

LRESULT APIENTRY WndProc3 (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static PARAMS params ;
	
	switch (message)
	{
	case WM_CREATE:
		params.hwnd = hwnd ;
		params.cyChar = HIWORD (GetDialogBaseUnits ()) ;
		_beginthread (Thread3, 0, ¶ms) ;
		return 0 ;
		
	case WM_SIZE:
		params.cyClient = HIWORD (lParam) ;
		return 0 ;
		
	case WM_DESTROY:
		params.bKill = TRUE ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}

//窗口4:画半径随机的椭圆

void Thread4 (PVOID pvoid)
{
	HDC		hdc ;
	int		iDiameter ;
	PPARAMS pparams ;
	
	pparams = (PPARAMS) pvoid ;
	
	while (!pparams->bKill)
	{
		InvalidateRect (pparams->hwnd, NULL, TRUE) ;
		UpdateWindow (pparams->hwnd) ;
		
		iDiameter = rand() % (max (1,
						  min (pparams->cxClient, pparams->cyClient))) ;
		
		hdc = GetDC (pparams->hwnd) ;
		
		Ellipse (hdc, (pparams->cxClient - iDiameter) / 2,
				    (pparams->cyClient - iDiameter) / 2,
				    (pparams->cxClient + iDiameter) / 2,
				    (pparams->cyClient + iDiameter) / 2) ;
		
		ReleaseDC (pparams->hwnd, hdc) ;
	}
	//结束线程
	_endthread () ;
}


LRESULT APIENTRY WndProc4 (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static PARAMS params ;
	
	switch (message)
	{
	case WM_CREATE:
		params.hwnd = hwnd ;
		params.cyChar = HIWORD (GetDialogBaseUnits ()) ;
		//创建线程
		_beginthread (Thread4, 0, ¶ms) ;
		return 0 ;
		
	case WM_SIZE:
		params.cxClient = LOWORD (lParam) ;
		params.cyClient = HIWORD (lParam) ;
		return 0 ;
		
	case WM_DESTROY:
		params.bKill = TRUE ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}

//主窗口的回调函数

LRESULT APIENTRY WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HWND    hwndChild[4] ;
	static TCHAR * szChildClass[] = { TEXT ("Child1"), TEXT ("Child2"),
							    TEXT ("Child3"), TEXT ("Child4") } ;
	static WNDPROC ChildProc[] = { WndProc1, WndProc2, WndProc3, WndProc4 } ;
	HINSTANCE	 hInstance ;
	int		  i, cxClient, cyClient ;
	WNDCLASS	  wndclass ;
	
	switch (message)
	{
	case WM_CREATE:
		hInstance = (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE) ;
		
		wndclass.style	    = CS_HREDRAW | CS_VREDRAW ;
		wndclass.cbClsExtra    = 0 ;
		wndclass.cbWndExtra    = 0 ;
		wndclass.hInstance	= hInstance ;
		wndclass.hIcon	    = NULL ;
		wndclass.hCursor	  = LoadCursor (NULL, IDC_ARROW) ;
		wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
		wndclass.lpszMenuName  = NULL ;
		
		for (i = 0 ; i < 4 ; i++)
		{
			wndclass.lpfnWndProc   = ChildProc[i] ;
			wndclass.lpszClassName = szChildClass[i] ;
			
			RegisterClass (&wndclass) ;
			
			hwndChild[i] = CreateWindow (szChildClass[i], NULL,
							WS_CHILDWINDOW | WS_BORDER | WS_VISIBLE,
							0, 0, 0, 0, 
							hwnd, (HMENU) i, hInstance, NULL) ;
		}
		
		return 0 ;
		
	case WM_SIZE:
		cxClient = LOWORD (lParam) ;
		cyClient = HIWORD (lParam) ;
		
		for (i = 0 ; i < 4 ; i++)
			MoveWindow (hwndChild[i], (i % 2) * cxClient / 2,
								 (i > 1) * cyClient / 2,
					  cxClient / 2, cyClient / 2, TRUE) ;
		return 0 ;
		
	case WM_CHAR:
		if (wParam == '\x1B')
			DestroyWindow (hwnd) ;
		
		return 0 ;
		
	case WM_DESTROY:
		PostQuitMessage (0) ;
		return 0 ;
	}
	return DefWindowProc (hwnd, message, wParam, lParam) ;
}


 

多线程程序的架构是这样的:你的主执行绪建立您程序所需要的所有窗口,并在其中包含所有的窗口消息处理程序,以便处理这些窗口的所有消息;所有其它执行绪只进行一些背景处理,除了和主执行绪通讯,它们不和使用者进行交流。

可以把这种架构想象成:主线程处理使用者输入(和其它消息),并建立程序中的其它线程,这些附加的线程完成与使用者无关的工作。

两个程序区别不大。主要在于WM_CREATE消息处理期间呼叫_beginthread函数来建立另一个线程。

注意:

注意如果你使用的是较老的编译器,比如VC++6.0,需要在「Project Settings」对话框中做一些修改。选择「C/C++」页面标签,然后在「Category」下拉式清单方块中选择「Code Generation」。在「Use Run-Time Library」下拉式清单方块中,可以看到用于「Release」设定的「Single-Threaded」和用于Debug设定的「Debug Single-Threaded」。将这些分别改为「Multithreaded」和「Debug Multithreaded」。但是如果使用的是VS2010,这些改动就不是必须的了。

我们可以看到第二个程序的运行速度明显比第一个快很多。从我的电脑的CPU使用率也可以发现,第一个程序的使用率只有10%左右,第二个达到了80%。

虽然多线程程序运行起来速度很快,但是很多人还是不建议使用它,因为有些时候,会出现线程的切换会产生很严重但又难以察觉的后果,比如线程间必须同步,这需要很多保护机制来避免它们。

 

你可能感兴趣的:(windows程序设计(18):多线程程序设计)