1. 程式人生 > >C++ 之 CreateThread 與beginThreadex用法具體示例解析 多執行緒 (三)

C++ 之 CreateThread 與beginThreadex用法具體示例解析 多執行緒 (三)

首先在此感謝 MoreWindows 秒殺多執行緒面試題系列讓我成長和學習!

在此再一次真心的感謝!

1  CreateThread示例

#include <iostream>
#include <Windows.h>
using namespace std;

DWORD WINAPI threadone(LPVOID lpParamter)
{
	cout<<"執行緒1執行" <<endl;
	return 0;
}
DWORD WINAPI threadtwo(LPVOID lpParamter)
{
	cout<<"執行緒2執行"<<endl;
	return 0;
} 

int main()
{
	while (1)
	{
		HANDLE haddle =  CreateThread(NULL, 0, threadone, NULL, 0, NULL);
		if (NULL == haddle)
		{
			cout<<"執行緒建立失敗:!" <<endl;
		}
	    
		WaitForSingleObject(haddle, 50000);
		

		HANDLE handle1 = CreateThread(NULL, 0, threadtwo, NULL, 0, NULL);
		if (NULL == handle1)
		{
			cout<<"執行緒建立失敗!"<<endl;
		}
				WaitForSingleObject(haddle, 5000);
	}
	
	
	system("pause");
	return 0;
}

執行效果:

#include <windows.h>
#include <process.h>
#include <iostream>
using namespace std;
unsigned Counter; 

unsigned __stdcall SecondThreadFunc( PVOID pArguments )
{
	printf( "In second thread...\n" );
	while ( Counter < 1000000 )
		Counter++;

	_endthreadex( 0 );
	return 0;
} 

int main()
{ 
	HANDLE hThread;
	unsigned threadID;
	// Create the second thread.
	hThread = (HANDLE)_beginthreadex( NULL, 0, &SecondThreadFunc, NULL, 0, &threadID );

	WaitForSingleObject( hThread, INFINITE );
	printf( "Counter should be 1000000; it is-> %d\n", Counter );
	cout<<threadID<<endl;
	// Destroy the thread object.
	CloseHandle( hThread );

	system("pause");
}


執行效果:

3 下篇將要使用的函式說明

使用者模式的執行緒同步機制效率高,如果需要考慮執行緒同步問題,應該首先考慮使用者模式的執行緒同步方法。

  但是,使用者模式的執行緒同步有限制,對於多個程序之間的執行緒同步,使用者模式的執行緒同步方法無能為力。這時,只能考慮使用核心模式。

  Windows提供了許多核心物件來實現執行緒的同步。對於執行緒同步而言,這些核心物件有兩個非常重要的狀態:“已通知”狀態,“未通知”狀態(也有翻譯為:受信狀態,未受信狀態)。Windows提供了幾種核心物件可以處於已通知狀態和未通知狀態:程序、執行緒、作業、檔案、控制檯輸入/輸出/錯誤流、事件、等待定時器、訊號量、互斥物件。

  你可以通知一個核心物件,使之處於“已通知狀態”,然後讓其他等待在該核心物件上的執行緒繼續執行。你可以使用Windows提供的API函式,等待函式來等待某一個或某些核心物件變為已通知狀態。

  你可以使用WaitForSingleObject函式來等待一個核心物件變為已通知狀態:

DWORD WaitForSingleObject(
   HANDLE hObject,     //指明一個核心物件的控制代碼
   DWORD dwMilliseconds);     //等待時間
  該函式需要傳遞一個核心物件控制代碼,該控制代碼標識一個核心物件,如果該核心物件處於未通知狀態,則該函式導致執行緒進入阻塞狀態;如果該核心物件處於已通知狀態,則該函式立即返回WAIT_OBJECT_0。第二個引數指明瞭需要等待的時間(毫秒),可以傳遞INFINITE指明要無限期等待下去。如果等待超時,該函式返回WAIT_TIMEOUT。如果該函式失敗,返回WAIT_FAILED。可以通過下面的程式碼來判斷:

DWORD dw = WaitForSingleObject(hProcess, 5000); //等待一個程序結束
switch (dw)
{
   case WAIT_OBJECT_0:
      // hProcess所代表的程序在5秒內結束
       break;

   case WAIT_TIMEOUT:
      // 等待時間超過5秒
       break;

   case WAIT_FAILED:
      // 函式呼叫失敗,比如傳遞了一個無效的控制代碼
       break;
}
  
還可以使用WaitForMulitpleObjects函式來等待多個核心物件變為已通知狀態:

DWORD WaitForMultipleObjects(
   DWORD dwCount,     //等待的核心物件個數
   CONST HANDLE* phObjects,     //一個存放被等待的核心物件控制代碼的陣列
   BOOL bWaitAll,     //是否等到所有核心物件為已通知狀態後才返回
   DWORD dwMilliseconds);     //等待時間
  該函式的第一個引數指明等待的核心物件的個數,可以是0到MAXIMUM_WAIT_OBJECTS(64)中的一個值。phObjects引數是一個存放等待的核心物件控制代碼的陣列。bWaitAll引數如果為TRUE,則只有當等待的所有核心物件為已通知狀態時函式才返回,如果為FALSE,則只要一個核心物件為已通知狀態,則該函式返回。第四個引數和WaitForSingleObject中的dwMilliseconds引數類似。

  該函式失敗,返回WAIT_FAILED;如果超時,返回WAIT_TIMEOUT;如果bWaitAll引數為TRUE,函式成功則返回WAIT_OBJECT_0,如果bWaitAll為FALSE,函式成功則返回值指明是哪個核心物件收到通知。

  可以如下使用該函式:

HANDLE h[3];     //控制代碼陣列

//三個程序控制代碼
h[0] = hProcess1;
h[1] = hProcess2;
h[2] = hProcess3;

DWORD dw = WaitForMultipleObjects(3, h, FALSE, 5000); //等待3個程序結束

switch (dw)
{
   case WAIT_FAILED:
      // 函式呼叫失敗
       break;

   case WAIT_TIMEOUT:
      // 超時
       break;

   case WAIT_OBJECT_0 + 0:
      // h[0](hProcess1)所代表的程序結束
       break;

   case WAIT_OBJECT_0 + 1:
      // h[1](hProcess2)所代表的程序結束
       break;

   case WAIT_OBJECT_0 + 2:
      // h[2](hProcess3)所代表的程序結束
       break;
}
  
你也可以同時通知一個核心物件,同時等待另一個核心物件,這兩個操作以原子的方式進行:

DWORD SignalObjectAndWait(
   HANDLE hObjectToSignal,   //通知的核心物件
   HANDLE hObjectToWaitOn,   //等待的核心物件
   DWORD dwMilliseconds,     //等待的時間
   BOOL bAlertable);         //與IO完成埠有關的引數,暫不討論
  該函式在內部使得hObjectToSignal引數所指明的核心物件變成已通知狀態,同時等待hObjectToWaitOn引數所代表的核心物件。dwMilliseconds引數的用法與WaitForSingleObject函式類似。
  該函式返回如下:WAIT_OBJECT_0,WAIT_TIMEOUT,WAIT_FAILED,WAIT_IO_COMPLETION。

  等你需要通知一個互斥核心物件並等待一個事件核心物件的時候,可以這麼寫:

ReleaseMutex(hMutex);
WaitForSingleObject(hEvent, INFINITE);
  可是,這樣的程式碼不是以原子的方式來操縱這兩個核心物件。因此,可以更改如下:

SignalObjectAndWait(hMutex, hEvent, INFINITE, FALSE);

期待將持續更新(將說明CRITICAL_SECTION的引數含義和臨界區的聯絡)!

如果覺得本文對您有幫助,請點選‘頂’支援一下,您的支援是我寫作最大的動力,謝謝。

注:以上在VS2010 下執行編譯!