c++におけるSetEventとResetEventの使用


イベントイベント(Event)はWIN 32が提供する最も柔軟なスレッド間同期方式であり、イベントは励起状態(signaled or true)または非励起状態(unsignal or false)であってもよい.状態遷移方式によっては,(1)手動設定,(1)このオブジェクトはプログラムによる手動設定のみ可能であり,そのイベントまたはイベント発生が必要な場合にはSetEventおよびResetEventを用いて設定する.(2)自動リカバリ:イベントが発生して処理されると、自動的にイベントがない状態にリカバリされ、再設定する必要はありません.イベントを作成する関数のプロトタイプは次のとおりです.
HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,//SECURITY_ATTRIBUTES構造ポインタは、NULL BOOL bManualReset、//手動/自動//TRUE:WaitForSingleObject後にResetEventクリア信号//FALSE:WaitForSingleObject後、システムはイベント信号BOOL bInitialStateを自動的にクリアし、//初期状態LPCTSTR lpName//イベント名);
「イベント」メカニズムを使用するには、(1)プロセス間でイベントにアクセスする場合は、イベントに名前を付ける必要があります.イベントに名前を付けるときは、システムネーミングスペース内の他のグローバルネーミングオブジェクトと衝突しないように注意してください.(2)イベントが自動的に復元されるかどうか.(3)イベントの初期状態設定.
次のコードを見てください.
DWORD WINAPI ThreadProc(LPVOID lpParam);  
DWORD WINAPI ThreadProc2(LPVOID lpParam);  

DWORD g_dwThreadID;  
DWORD g_dwThreadID2;  

UINT g_nTickets = 300;  //int g_nTickets = 300;  //  1
HANDLE g_hEvent = NULL;  

HANDLE g_hEvent1 = NULL; 
HANDLE g_hEvent2 = NULL; 

CRITICAL_SECTION g_cs;

int ThreadCout = 0;

int main()  
{  
	cout << "Main thread is running." << endl;  

	InitializeCriticalSection(&g_cs);//      
	
	HANDLE hHandle = CreateThread(NULL, 0, ThreadProc, NULL, 0, &g_dwThreadID);  
	ThreadCout++;
	HANDLE hHandle2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, &g_dwThreadID2); 
	ThreadCout++;

	//g_hEvent = CreateEvent(NULL, FALSE,  TRUE, NULL);  
	g_hEvent1 = CreateEvent(NULL, FALSE,  TRUE, NULL);  //  5:g_hEvent1 = CreateEvent(NULL, TRUE,  TRUE, NULL);
	g_hEvent2 = CreateEvent(NULL, FALSE,  TRUE, NULL);	//  5:g_hEvent2 = CreateEvent(NULL, TRUE,  TRUE, NULL);

	ResetEvent(g_hEvent1);
	ResetEvent(g_hEvent2);

	SetEvent(g_hEvent1); 


	while (TRUE)
	{
		EnterCriticalSection(&g_cs);
		int nCount = ThreadCout;  
		LeaveCriticalSection(&g_cs);

		if (nCount == 0)
		{
			cout << "Main thread is break." << endl; 
			break;
		}

	}

	
	Sleep(1000);	//  4	
	
	CloseHandle(hHandle);   
	CloseHandle(hHandle2);  

	DeleteCriticalSection(&g_cs);

	cout << "Main thread is end." << endl;

	system("pause");  
	return 0;  
}  

DWORD WINAPI ThreadProc(LPVOID lpParam)  
{   
	// cout << "No." << g_dwThreadID << " thread is running." << endl;  
	while (TRUE)  
	{  
		WaitForSingleObject(g_hEvent1, INFINITE);  
		cout << "No.1 " << g_dwThreadID << " thread is running." << endl;  

		EnterCriticalSection(&g_cs);
		int temp= g_nTickets; 
		LeaveCriticalSection(&g_cs);

		cout << "No.1 " << g_dwThreadID << " thread is temp." << endl; 

		if (temp > 0)  
		{  
			Sleep(10);  //Sleep(1000)	//  2
			cout << "No.1-" << g_dwThreadID << " sell ticket : " << temp << endl; 
			
			
			EnterCriticalSection(&g_cs);
			g_nTickets--;  
			LeaveCriticalSection(&g_cs);

			SetEvent(g_hEvent2); 
			//ResetEvent(g_hEvent1);//  6
			  

		}  
		else  
		{  
			cout << "No.1- break" << endl;
			//ResetEvent(g_hEvent1);//  6
			SetEvent(g_hEvent2);//    ThreadProc2    	//  3
			break;  
		}  
	}  

	EnterCriticalSection(&g_cs);
	ThreadCout--;  
	LeaveCriticalSection(&g_cs);
	cout << "No.1- end" << endl;

	return 0;  
}  

DWORD WINAPI ThreadProc2(LPVOID lpParam)  
{  
	// 
	while (TRUE)  
	{  
		WaitForSingleObject(g_hEvent2, INFINITE);  
		cout << "No.2 " << g_dwThreadID2 << " thread is running." << endl;  

		EnterCriticalSection(&g_cs);
		int temp= g_nTickets; 
		LeaveCriticalSection(&g_cs);

		if (temp > 0)  
		{  
			Sleep(10);  //Sleep(1000)	//  2
			cout << "No.2-" << g_dwThreadID2 << " sell ticket : " << temp << endl;  

			EnterCriticalSection(&g_cs);
			g_nTickets--;  
			LeaveCriticalSection(&g_cs);

			SetEvent(g_hEvent1); 
			//ResetEvent(g_hEvent2);//  6
		}  
		else  
		{  
			cout << "No.2- break" << endl;
			//ResetEvent(g_hEvent2);//  6
			SetEvent(g_hEvent1);//     ,    ThreadProc    		//  3
			break;  
		}  
	}  

	EnterCriticalSection(&g_cs);
	ThreadCout--;  
	LeaveCriticalSection(&g_cs);

	cout << "No.2- end" << endl;
	return 0;  
}  

このコードは,前回のUINT型のループ変数としての不確実性に関する問題に続き,臨界領域制御グローバル変数へのアクセスを加えたものである.
ここで説明するのは、SetEventとResetEventの使用です.これは、注釈5と注釈6を参照してください.
備考5箇所:
CreateEventの2番目のパラメータは、ResetEventを手動で呼び出す必要があるかどうかを決定します.TRUEの場合、手動で呼び出す必要がありますが、呼び出さなければどうなりますか.呼び出さないと、イベントは常に信号状態、すなわち注釈6にあります.FALSEの場合、手動で呼び出す必要はありません.呼び出す必要はありません.効果は同じです.ResetEventを
WaitForSingleObjectの前でも良い方法です.
転載はオリジナルリンクを明記してください:http://blog.csdn.net/wujunokay/article/details/12272581