1. 程式人生 > >windows下多執行緒同步

windows下多執行緒同步

互斥量(鎖)

適用範圍:可以跨程序同步,還可以用來保證程式只有一個互斥鎖例項執行(建立命名互斥量),也可以用來做執行緒間的同步

如果用於程序間同步,一個執行緒建立互斥量物件後,另一個程序只需要獲取互斥量就可以,可以用OpenMutex(MUTEX_ALL_ACCESS,FALSE,"TesthMutex")函式獲取

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


int money=0;
HANDLE hMutex;
//執行緒1回撥函式
//希望兩個執行緒把monery加到100,執行緒1休眠的時候讓執行緒2去處理
DWORD WINAPI  ThreadFun1(LPVOID args)
{
	while(true)
	{
		/*
		*檢測hHandle事件的訊號狀態函式詳細說明
		*DWORD WINAPI WaitForSingleObject(
		__in HANDLE hHandle,
		__in DWORD dwMilliseconds
		);
		*返回值:執行成功,返回值指示出引發函式返回的事件。它可能為以下值:
		 WAIT_OBJECT_0 0x00000000 :指定的物件出有有訊號狀態
		 WAIT_TIMEOUT 0x00000102:等待超時
		 WAIT_FAILED 0xFFFFFFFF :出現錯誤,可通過GetLastError得到錯誤程式碼
		*引數說明:
		*hHandle	物件控制代碼,可以指定一系列的物件,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等
		*dwMilliseconds]定時時間間隔,單位為milliseconds(毫秒).如果指定一個非零值,函式處於等待狀態直到hHandle標記的物件被觸發,或者時間到了\
		 如果dwMilliseconds為0,物件沒有被觸發訊號,函式不會進入一個等待狀態,它總是立即返回。如果dwMilliseconds為INFINITE,物件被觸發訊號後,函式才會返回
		*/

		//等待互斥物件的訊號,INFINITE表示一直等待,對之後的程式碼進行保護,有訊號立即返回
		WaitForSingleObject(hMutex,INFINITE);
		if(money<100)
		{
			++money;
			cout<<"thred1 money:"<<money<<endl;
			ReleaseMutex(hMutex);//釋放指定互斥物件的所有權,互斥物件變為已通知狀態,執行緒2就能獲取到互斥物件
		}
		else
		{
			break;
		}
		
	}
	return 0;
}


//執行緒2回撥函式
DWORD WINAPI  ThreadFun2(LPVOID args)
{
	while(true)
	{
		WaitForSingleObject(hMutex,INFINITE);
		Sleep(1);
		if(money<100)
		{
			++money;
			cout<<"thred2 money:"<<money<<endl;
			ReleaseMutex(hMutex);
		}
		else
		{
			break;
		}
		
	}
	return 0;
}


	
int main()
{
	HANDLE Thread1,Thread2;
	/*
	建立執行緒函式詳細說明
	*HANDLE WINAPI CreateThread(
	__in_opt  LPSECURITY_ATTRIBUTES lpThreadAttributes,
	__in      SIZE_T dwStackSize,
	__in      LPTHREAD_START_ROUTINE lpStartAddress,
	__in_opt __deref __drv_aliasesMem LPVOID lpParameter,
	__in      DWORD dwCreationFlags,
	__out_opt LPDWORD lpThreadId
	);
	*返回值:函式成功,返回執行緒控制代碼;函式失敗返回false。若不想返回執行緒ID,設定值為NULL
	*引數說明:
	*lpThreadAttributes	執行緒安全性,使用預設安全性,一般預設null
	*dwStackSize	堆疊大小,0為預設大小
	*lpStartAddress	執行緒要執行的函式指標,即入口函式
	*lpParameter	執行緒引數
	*dwCreationFlags	執行緒標記,如為0,則建立後立即執行
	*lpThreadId	LPDWORD為返回值型別,一般傳遞地址去接收執行緒的識別符號,一般設為null
	*/
	Thread1=CreateThread(NULL,0,ThreadFun1,NULL,0,NULL);
	if(Thread1==NULL)
	{
		cout<<"CreateThread1 fail"<<endl;
	}

	Thread2=CreateThread(NULL,0,ThreadFun2,NULL,0,NULL);
	if(Thread2==NULL)
	{
		cout<<"CreateThread2 fail"<<endl;
	}
	CloseHandle(Thread1);//關閉執行緒控制代碼,核心物件引用計數器減1,只有核心物件引用為0時才會釋放執行緒記憶體物件
	CloseHandle(Thread2);
	

	/*
	建立互斥物件函式詳細說明
	*HANDLE WINAPI CreateMutexA(
	__in_opt LPSECURITY_ATTRIBUTES lpMutexAttributes,
	__in     BOOL bInitialOwner,
	__in_opt LPCSTR lpName
	);		
	*返回值:如執行成功,就返回互斥體物件的控制代碼;零表示出錯。會設定GetLastError。如果返回的是一個有效控制代碼,但指定的名字已經存在,GetLastError也會設為ERROR_ALREADY_EXISTS,
	bInitialOwner的值將會被忽略。如果呼叫者限制了許可權,GetLastError將會返回ERROR_ACCESS_DENIED,這個時候應該使用OpenMutex函式。
	*引數說明:
	*lpMutexAttributes	指向安全屬性的指標
	*bInitialOwner	初始化互斥物件的所有者
	*lpName	指向互斥物件名的指標,如果填寫了就算是建立了一個命名的互斥物件,只能有一個test程序執行
	*/
	hMutex =CreateMutex(NULL,false,"test");     //建立命名互斥物件,且為有訊號狀態
	if(hMutex)
	{
		if(ERROR_ALREADY_EXISTS==GetLastError())
		{
			cout<<"已經有一個相同應用程式在執行!"<<endl;
			return 0;
		}
	}
	system("pause");
	CloseHandle(hMutex);
	return 0;
}	
	
	

事件物件

適用範圍:多用於執行緒間的通訊,可以跨程序同步

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


int money=0;
HANDLE hEvent;//定義事件控制代碼
DWORD WINAPI Thread1(LPVOID lpThreadParameter)
{
	while(true)
	{
		WaitForSingleObject(hEvent,INFINITE);//當執行緒獲取到訊號時,作業系統會自動把事件物件設定為無訊號因為我CreateEvent函式第二個引數設定為自動的
		Sleep(1);
		if(money<100)
		{
			++money;
			cout<<"thred1 money:"<<money<<endl;
			/*
			*重置事件物件為有訊號
			*BOOL SetEvent(HANDLE hEvent);
			*返回值:如果操作成功,則返回非零值,否則為0
			*引數說明:
			*hEvent 設定控制代碼為有訊號
			*/
			SetEvent(hEvent);
		}
		else
		{
			break;
		}

	}
	return 0;
}

DWORD WINAPI Thread2(LPVOID lpThreadParameter)
{
	while(true)
	{
		WaitForSingleObject(hEvent,INFINITE);
		Sleep(1);
		if(money<100)
		{
			++money;
			cout<<"thred2 money:"<<money<<endl;
			SetEvent(hEvent);
		}
		else
		{
			break;
		}

	}
	return 0;
}
int main()
{
	
	HANDLE thred1,thred2;

	thred1=CreateThread(NULL,0,Thread1,NULL,0,NULL);
	if(thred1==NULL)
	{
		cout<<"CreateThread1 fail"<<endl;
	}

	thred2=CreateThread(NULL,0,Thread2,NULL,0,NULL);
	if(thred2==NULL)
	{
		cout<<"CreateThread1 fail"<<endl;
	}

	CloseHandle(thred1);//關閉執行緒控制代碼
	CloseHandle(thred2);


	/*
	*建立事件物件
	HANDLE WINAPI CreateEventA(
	__in_opt LPSECURITY_ATTRIBUTES lpEventAttributes,
	__in     BOOL bManualReset,
	__in     BOOL bInitialState,
	__in_opt LPCSTR lpName
	);
	*返回值:如果函式呼叫成功,函式返回事件物件的控制代碼。如果對於命名的物件,在函式呼叫前已經被建立,函式將返回存在的事件物件的控制代碼,而且在GetLastError函式中返回ERROR_ALREADY_EXISTS。
	如果函式失敗,函式返回值為NULL,如果需要獲得詳細的錯誤資訊,需要呼叫GetLastError。
	*引數說明:
	*lpEventAttributes	安全性,採用null預設安全性。
	*bManualReset	(TRUE)人工重置或(FALSE)自動重置事件物件為非訊號狀態,若設為人工重置,則當事件為有訊號狀態時,所有等待的執行緒都變為可排程執行緒。
	*bInitialState		指定事件物件的初始化狀態,TRUE:初始為有訊號狀態。
	*lpName	事件物件的名字,一般null匿名即可
	*/
	hEvent=CreateEvent(NULL,false,true,NULL);
	if(hEvent==NULL)
	{
		cout<<"CreateEvent fail"<<endl;
	}
	system("pause");
	CloseHandle(hEvent);
	return 0;
}