本文目的:用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,在下篇博客中,我將會把關鍵代碼段鎖添加進來,並且對Mutex和CRITICAL_SECTION的性能做以比較
摘自 chexlong的專欄