1. 程式人生 > >c++ 多執行緒 事件EVENT

c++ 多執行緒 事件EVENT

事件是核心物件。事件的常用函式:

CreateEvent

函式功能:建立事件

函式原型:

HANDLE CreateEvent(

LPSECURITY_ATTRIBUTES lpEventAttributes,

BOOL bManualReset,

BOOL bInitialState,

LPCTSTR pName

);

第一個引數表示安全控制,一般直接傳入NULL。

第二個引數確定事件是手動置位還是自動置位,傳入TRUE表示手動置位,傳入FALSE表示自動置位。如果為自動置位,則對該事件呼叫WaitForSingleObject()後會自動呼叫ResetEvent()使事件變成未觸發狀態。

第三個引數表示事件的初始狀態,傳入TRUE表示已觸發。

第四個引數表示事件的名稱,傳入NULL表示匿名事件。

OpenEvent

函式功能:根據名稱獲得一個事件控制代碼。

函式原型:

HANDLE OpenEvent(

DWORD dwDesiredAccess,

BOOL bInheritHandle,

LPCTSTRl pName //名稱

);

函式說明:

第一個引數表示訪問許可權,對事件一般傳入EVENT_ALL_ACCESS。

第二個引數表示事件控制代碼繼承性,一般傳入TRUE即可。

第三個引數表示名稱,不同程序中的各執行緒可以通過名稱來確保它們訪問同一個事件。

SetEvent

函式功能:觸發事件

函式原型:BOOLSetEvent(HANDLEhEvent);

函式說明:每次觸發後,必有一個或多個處於等待狀態下的執行緒變成可排程狀態。

ResetEvent

函式功能:將事件設為末觸發

函式原型:BOOLResetEvent(HANDLEhEvent);

 CloseHandle

清理與銷燬

由於事件是核心物件,因此使用CloseHandle()就可以完成清理與銷燬了。

多執行緒中的除錯,由於除錯是對於當前執行緒的,所以就導致一個出不來的情況,即執行緒中斷後,你點繼續,然後作業系統有將執行緒執行,而導致除錯時執行緒永遠是強制中斷,強制執行,而不會進入其他執行緒。。。

執行緒同步主要研究的問題是,由於建立多個執行緒,而執行緒的執行的順序是不定的,導致出現一些不合理的情況,所以提出同步的概念,使執行緒按照一定順序執行。

總結一下同步互斥,我們有可以發現,同步互斥都不是針對某塊資源實現的,而是在任何情況下訪問任何資源的可以同步互斥,而真正的同步互斥是在對共享資源進行操作的程式碼處加上同步互斥的約定,使對這些共享資源的訪問是同步互斥的,而不是在一些執行緒自己的資源上也進行同步互斥的費操作。

如下是事件的程式碼實現。

HANDLE mutex = INVALID_HANDLE_VALUE;

HANDLE event;
typedef struct param{
	int a;
	bool b;
	double c;
	string d;
};

unsigned int __stdcall threadfun1(LPVOID p){
	Sleep(100);
	//呼叫等待互斥量未觸發,將其有未觸發改為觸發
	WaitForSingleObject(mutex,INFINITE);
	param* funparam = (param*) p;
	cout<<"fun1 running:"<<funparam->d<<endl;
	funparam->c *= funparam->a; 
	cout<<"ans:"<<funparam->c<<endl;
	//釋放互斥量,改為未觸發
	ReleaseMutex(mutex);
	return 0;
}
DWORD __stdcall threadfun2(LPVOID p){
	Sleep(100);
	//呼叫等待互斥量未觸發,將其有未觸發改為觸發
	WaitForSingleObject(mutex,INFINITE);
	SetEvent(event);
	param* funparam = (param*) p;
	cout<<"fun2 running:"<<funparam->d<<endl;
	funparam->c /= (1+funparam->a);
	cout<<funparam->a<<"\nans:"<<funparam->c<<endl;
	//釋放互斥量,改為未觸發
	ReleaseMutex(mutex);
	return 0;
}

int main(){
	param p={1,true,9.995,"hello world"};
	//A表示字串使用的是ASCII編碼集,預設為UNICODE,即W。
	//第二個引數為false,表示互斥量未觸發,當為true表示已觸發。
	mutex = CreateMutexA(NULL,false,"MUTEX");
	//對於程序間的互斥,在一個程序建立互斥量,然後在另外一個程序開啟互斥量
	mutex = OpenMutexA(MUTEX_ALL_ACCESS,true,"MUTEX");
	HANDLE newthread1 = (HANDLE)_beginthreadex(NULL,0,threadfun1,&p,0,NULL);
	event = CreateEvent(NULL,false,false,NULL);
	const int THREADNUM = 10;
	HANDLE newthread2[THREADNUM];
	int &i =p.a;
	while(i<THREADNUM){
		newthread2[i]= CreateThread(NULL,0,threadfun2,&p,0,NULL);
		WaitForSingleObject(event,INFINITE);
		//WaitForSingleObject(newthread2[i],INFINITE);
		i++;
	}
	WaitForMultipleObjects(THREADNUM,newthread2,true,INFINITE);
	//WaitForSingleObject(newthread2,INFINITE);
	WaitForSingleObject(newthread1,INFINITE);
	CloseHandle(mutex);
	CloseHandle(event);
	system("PAUSE");
}

實際上,我們發現同步只是讓一個執行緒一些步驟完成後,其他執行緒就可以繼續進行。這裡是同步。

對於這裡,使用自動檔,使用waitforsingleobject來使事件未觸發,而用手動檔,呼叫ReleaseEvent()釋放。

仔細分析一下,發現其實同步根本沒有你們複雜,就比如這個地方,要實現執行緒的先後順序,只要等待一個執行緒完成即可,直接使用WaitForSingleObject(newthread2[i],INFINITE)就可以等待 第i個執行緒完成後再執行下一步,即實現同步,也可以改為釋放互斥量或退出臨界區的操作。

實際上執行緒同步就是互斥,而只要對互斥進行一點簡單的變形就可以得到同步,如等待同步。所以同步互斥都是可以用一種方法來實現的,但為什麼會有同步互斥,以及這些大同小異的方法呢?