Win32API下的多執行緒程式設計入門

whatchacha發表於2014-08-08


多執行緒,Multi-Thread。移步別處理解Thread和Process。多執行緒可用多種API實現,這裡用Win32 API實現最簡單的多執行緒,執行緒彼此獨立,不涉及執行緒間的資料共享。

先直接上程式:

#include <stdio.h>
#include <windows.h>
#include <process.h>
#include <string>
#include <iostream>

class ThreadX
{
private:
	std::string threadName;
	int loopStart;
	int loopEnd;
	int loopStep;
public:
	ThreadX(int x, int y, int z) : loopStart(x), loopEnd(y), loopStep(z) { }
	void SetThreadName(std::string name)
	{
		threadName = name;
	}
	static unsigned __stdcall ThreadEntryPoint(void* pThis)
	{
		ThreadX* pTh = (ThreadX*)pThis;
		pTh->StartUp();

		return 1;
	}
	void StartUp()
	{
		for (int i = loopStart; i < loopEnd; ++i)
		{
			if (i % loopStep == 0)
			{
				//std::cout << threadName << ": " << i << std::endl;
				printf("%s : %d \n", threadName.c_str(), i);
			}
		}
		printf("%s terminating...\n", threadName.c_str());
	}
};

int main()
{
	ThreadX* obj1 = new ThreadX(0, 1000000, 20000);
	obj1->SetThreadName("Thread1");
	HANDLE hThread1;
	unsigned thread1Id;
	hThread1 = (HANDLE)_beginthreadex(NULL,
		0,
		ThreadX::ThreadEntryPoint,
		obj1,
		CREATE_SUSPENDED,
		&thread1Id);
	if (hThread1 == NULL)
	{
		printf("Failed to create Thread 1. \n");
	}
	DWORD dwExitCode;
	GetExitCodeThread(hThread1, &dwExitCode);
	printf("initial thread 1 exit code = %d \n", dwExitCode);

	ThreadX* obj2 = new ThreadX(-1000000, 0, 20000);
	obj2->SetThreadName("Thread2");
	HANDLE hThread2;
	unsigned thread2Id;
	hThread2 = (HANDLE)_beginthreadex(NULL,
		0,
		ThreadX::ThreadEntryPoint,
		obj2,
		CREATE_SUSPENDED,
		&thread2Id);
	if (hThread2 == NULL)
	{
		printf("Failed to create Thread 1. \n");
	}
	GetExitCodeThread(hThread1, &dwExitCode);
	printf("initial thread 2 exit code = %d \n", dwExitCode);

	ResumeThread(hThread1);
	ResumeThread(hThread2);

	WaitForSingleObject(hThread1, INFINITE);
	WaitForSingleObject(hThread2, INFINITE);

	GetExitCodeThread(hThread1, &dwExitCode);
	printf("thread 1 exit with code : %d \n", dwExitCode);

	GetExitCodeThread(hThread2, &dwExitCode);
	printf("thread 2 exit with code : %d \n", dwExitCode);

	CloseHandle(hThread1);
	CloseHandle(hThread2);

	delete(obj1);
	obj1 = NULL;
	delete(obj2);
	obj2 = NULL;

	system("pause");
	return 0;
}

執行結果如下:

記錄以下幾點。

1. 

hThread1 = (HANDLE)_beginthreadex(NULL,
0,
ThreadX::ThreadEntryPoint,
obj1,
CREATE_SUSPENDED,
&thread1Id);

ResumeThread(hThread1);

WaitForSingleObject(hThread1, INFINITE);

GetExitCodeThread(hThread1, &dwExitCode);

CloseHandle(hThread1);

這個Sample裡用到的關於多執行緒的Win32 API就上面的幾個粗體標示的函式。

注意:

(1)用_beginthreadex 而非CreateThread,因為CreateThread用於CRT時會導致記憶體洩露。

官方說明如下:http://msdn.microsoft.com/en-us/library/windows/desktop/ms682453(v=vs.85).aspx

A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and_endthreadex functions for thread management rather than CreateThread and ExitThread; this requires the use of the multithreaded version of the CRT. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions.” 

(2) _beginthreadex 建立的程式被Suspend了,所以才需要後面的ResumeThread(hThread1) 將程式喚醒。

(3)當執行緒還存活時,GetExitCodeThread返回的是259,當執行緒執行結束時,返回的是1.


2. 

輸出資訊時,推薦用printf,不容易被其他進行插斷。用cout時,stream容易在不同Thread中跳轉。 如果將StartUp()函式裡的資訊輸入用註釋的那行代替printf那行,執行結果容易出現這種問題:




3.

為了顯示出多執行緒的同時執行,即最終的執行結果裡Thread1和Thread2的資訊穿插輸出,需要保證StartUp()裡迴圈的次數夠多才輸出資訊,否則其他Thread來不及插隊列印資訊。

比如,將

ThreadX* obj1 = new ThreadX(0, 1000000, 20000);

ThreadX* obj2 = new ThreadX(-1000000, 0, 20000);

改為

ThreadX* obj1 = new ThreadX(10, 600, 7);

ThreadX* obj2 = new ThreadX(10001, 10900, 9);

執行結果就變為:


即看起來像是一個執行緒執行結束後才開始另一個執行緒。 不是我們想看到的效果-_-


最後,推薦一個多執行緒入門的教程:http://www.codeproject.com/Articles/14746/Multithreading-Tutorial  ,講解和例子都很棒,尤其是前面4個例子。



相關文章