除了臨界區與互斥體,CSemaphore 信號量提供更靈活的同步機制:允許指定最大同時存取共享資源的線程數,類似作業系統 PV 操作。
信號量內部維護一個計數器。線程存取資源時計數遞減,歸零時阻塞後續線程;線程釋放資源時計數遞增,喚醒等待線程。
// 建立:初始計數 2,最大計數 2(允許 2 線程並發存取)
CSemaphore Semaphore(2, 2);
// 或動態建立
CSemaphore* pSemaphore = new CSemaphore(2, 2);
// 使用 CSingleLock 管理鎖定/解鎖
CSingleLock SingleLock(pSemaphore);
SingleLock.Lock(); // 計數 -1,若為 0 則阻塞
// ... 存取共享資源 ...
SingleLock.Unlock(); // 計數 +1,喚醒等待線程
#include "afxmt.h"
class CSharedResource
{
private:
CSemaphore* m_pSemaphore;
public:
CSharedResource() { m_pSemaphore = new CSemaphore(2, 2); }
~CSharedResource() { delete m_pSemaphore; }
void AccessResource()
{
CSingleLock lock(m_pSemaphore);
lock.Lock();
// ... 資源存取操作 ...
Sleep(1000); // 模擬耗時操作
lock.Unlock();
}
};
CSharedResource SharedResource; // 全域實例
UINT Thread_Proc1(LPVOID param)
{
SharedResource.AccessResource();
::MessageBox((HWND)param, "Thread #1 accessed!", "Thread Proc1", MB_OK);
return 0;
}
UINT Thread_Proc2(LPVOID param)
{
SharedResource.AccessResource();
::MessageBox((HWND)param, "Thread #2 accessed!", "Thread Proc2", MB_OK);
return 0;
}
UINT Thread_Proc3(LPVOID param)
{
SharedResource.AccessResource();
::MessageBox((HWND)param, "Thread #3 accessed!", "Thread Proc3", MB_OK);
return 0;
}
HWND hWnd = GetSafeHwnd();
AfxBeginThread(Thread_Proc1, hWnd);
AfxBeginThread(Thread_Proc2, hWnd);
AfxBeginThread(Thread_Proc3, hWnd);
前兩個線程取得信號量並存取資源,第三個線程阻塞等待。直到前兩者釋放,第三者才能進入。有效實現了多線程對共享資源的計數保護與資料同步。
本文為筆者多線程學習筆記,供參考交流。配套原始碼供下載。