1. 程式人生 > >用C++實現多執行緒Mutex鎖(Win32)

用C++實現多執行緒Mutex鎖(Win32)

    本文目的:用C++和Windows的互斥物件(Mutex)來實現執行緒同步鎖。

    準備知識:1,核心物件互斥體(Mutex)的工作機理,WaitForSingleObject函式的用法,這些可以從MSDN獲取詳情; 2,當兩個或更多執行緒需要同時訪問一個共享資源時,系統需要使用同步機制來確保一次只有一個執行緒使用該資源。Mutex 是同步基元,它只向一個執行緒授予對共享資源的獨佔訪問權。如果一個執行緒獲取了互斥體,則要獲取該互斥體的第二個執行緒將被掛起,直到第一個執行緒釋放該互斥體。

    下邊是我參考開源專案C++ Sockets的程式碼,寫的執行緒鎖類

Lock.h

#ifndef _Lock_H
#define _Lock_H

#include <windows.h>

//鎖介面類
class IMyLock
{
public:
	virtual ~IMyLock() {}

	virtual void Lock() const = 0;
	virtual void Unlock() const = 0;
};

//互斥物件鎖類
class Mutex : public IMyLock
{
public:
	Mutex();
	~Mutex();

	virtual void Lock() const;
	virtual void Unlock() const;

private:
	HANDLE m_mutex;
};

//鎖
class CLock
{
public:
	CLock(const IMyLock&);
	~CLock();

private:
	const IMyLock& m_lock;
};


#endif


Lock.cpp

#include "Lock.h"

//建立一個匿名互斥物件
Mutex::Mutex()
{
	m_mutex = ::CreateMutex(NULL, FALSE, NULL);
}

//銷燬互斥物件,釋放資源
Mutex::~Mutex()
{
	::CloseHandle(m_mutex);
}

//確保擁有互斥物件的執行緒對被保護資源的獨自訪問
void Mutex::Lock() const
{
	DWORD d = WaitForSingleObject(m_mutex, INFINITE);
}

//釋放當前執行緒擁有的互斥物件,以使其它執行緒可以擁有互斥物件,對被保護資源進行訪問
void Mutex::Unlock() const
{
	::ReleaseMutex(m_mutex);
}

//利用C++特性,進行自動加鎖
CLock::CLock(const IMyLock& m) : m_lock(m)
{
	m_lock.Lock();
}

//利用C++特性,進行自動解鎖
CLock::~CLock()
{
	m_lock.Unlock();
}


    下邊是測試程式碼

// MyLock.cpp : 定義控制檯應用程式的入口點。
//

#include <iostream>
#include <process.h>
#include "Lock.h"

using namespace std;

//建立一個互斥物件
Mutex g_Lock;


//執行緒函式
unsigned int __stdcall StartThread(void *pParam)
{
	char *pMsg = (char *)pParam;
	if (!pMsg)
	{
		return (unsigned int)1;
	}

	//對被保護資源(以下列印語句)自動加鎖
	//執行緒函式結束前,自動解鎖
	CLock lock(g_Lock);

	for( int i = 0; i < 5; i++ )
	{
		cout << pMsg << endl;
		Sleep( 500 );
	}

	return (unsigned int)0;
}

int main(int argc, char* argv[])
{
	HANDLE hThread1, hThread2;
	unsigned int uiThreadId1, uiThreadId2;

	char *pMsg1 = "First print thread.";
	char *pMsg2 = "Second print thread.";

	//建立兩個工作執行緒,分別列印不同的訊息

	//hThread1 = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartThread, (void *)pMsg1, 0, (LPDWORD)&uiThreadId1);
	//hThread2 = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartThread, (void *)pMsg2, 0, (LPDWORD)&uiThreadId2);

	hThread1 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)pMsg1, 0, &uiThreadId1);
	hThread2 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)pMsg2, 0, &uiThreadId2);

	//等待執行緒結束
	DWORD dwRet = WaitForSingleObject(hThread1,INFINITE);
	if ( dwRet == WAIT_TIMEOUT )
	{
		TerminateThread(hThread1,0);
	}
	dwRet = WaitForSingleObject(hThread2,INFINITE);
	if ( dwRet == WAIT_TIMEOUT )
	{
		TerminateThread(hThread2,0);
	}

	//關閉執行緒控制代碼,釋放資源
	::CloseHandle(hThread1);
	::CloseHandle(hThread2);

	system("pause");
	return 0;
}


    用VC2005編譯,啟動程式,下邊是截圖

    如果將測執行緒函式中的程式碼注視掉,重新編譯程式碼,執行

CLock lock(g_Lock);

     則結果見下圖

    由此可見,通過使用Mutex的封裝類,即可達到多執行緒同步的目的。因Mutex屬於核心物件,所以在進行多執行緒同步時速度會比較慢,但是用互斥物件可以在不同程序的多個執行緒之間進行同步。

    在實際應用中,我們通常還會用到臨界區,也有叫做關鍵程式碼段的CRITICAL_SECTION,在下篇部落格中,我將會把CRITICAL_SECTION鎖新增進來,並且對Mutex和CRITICAL_SECTION的效能做以比較。