1. 线程同步之临界区
临界区不涉及到内核切换,只需要在用户态进行切换,所以效率比较高。
基本使用流程:
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs); // 对应DeleteCriticalSection,只需调用一次。
EnterCriticalSection(&cs);
// ….
LeaveCriticalSection(&cs);
DeleteCriticalSection(&cs);
如果拥有临界区的线程意外终止,其他等待该临界区的线程会一直等待。
开发中经常对临界区进行如下封装:
class CritSec {
public:
CritSec() {
InitializeCriticalSection(&m_CS);
}
~CritSec() {
DeleteCriticalSection(&m_CS);
}
void Lock() {
EnterCriticalSection(&m_CS);
}
void Unlock() {
LeaveCriticalSection(&m_CS);
}
private:
CritSec(const CritSec &refCritSec);
CritSec &operator=(const CritSec &refCritSec);
CRITICAL_SECTION m_CS;
}
还可以再次封装一层:
class Locker {
public:
explicit Locker(CritSec *pCS) {
m_pCS = pCS;
m_pCS->Lock();
}
~Locker() {
m_pCS->Unlock();
}
private:
Locker(const Locker &lock);
Locker &operator=(const Locker &lock);
CritSec* m_pCS;
};
2. 线程同步之互斥体
HANDLE WINAPI CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
BOOL bInitialOwner,
LPCTSTR lpName
);
lpMutexAttributes:安全描述相关,如果需要跨线程共享该互斥体就需要设置该属性,否则只需要设置为NULL。
bInitialOwner:设置为TRUE表示创建线程持有该互斥体。如果为TRUE,则该线程创建完互斥体之后就持有该互斥体。
lpName:为互斥体指定名称,最大字符数为MAX_PATH。如果lpName为NULL,则创建没有名称的Mutex。
- 如果指定的名称和现有的事件(Event)、信号量(Semaphore)、文件映射(file-mapping)、任务(job)、定时器(waitable-timer)等相同,则函数返回NULL,GetLastError返回ERROR_INVALID_HADNLE。
如果指定的名称和现有的互斥体(Mutex)相同,且具有MUTEX_ALL_ACCESS权限,则返回该Handle,GetLastError返回ERROR_ALREADY_EXIST. - 名称以"Global\"开头,可以创建全局互斥体,在不同session间共享。
- 函数成功返回句柄,失败返回NULL。句柄使用完之后需要使用CloseHandle关闭,防止句柄泄漏。
- 互斥体在没有任何线程持有时,才是有信号状态。
- 在拥有互斥体的线程意外终止后,系统后自动将互斥体内部持有线程ID重置为0,这样该互斥体又被置为了有信号状态。(被选中的线程的WaitForSingleObject()会返回WAIT_ABANDONED_0)
ReleaseMutex
释放线程对互斥体的拥有,互斥体处于有信号(signal)状态。
BOOL WINAPI ReleaseMutex(
HANDLE hMutex
);
成功返回非0,失败返回0.

3. 线程同步之事件
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPTSTR lpName
);
lpEventAttributes:安全描述符,一般设置为NULL。
bManualReset:事件信号是自动重置还是手动重置。自动重置在信号被释放之后(如WaitForSingleObject系列函数非超时返回),自动重置为非信号状态。
这个特性是互斥体和信号量所不具有的。
bInitialState:初始状态是否有信号。
lpName :事件名称,同互斥体。
4. 线程同步之信号量
HANDLE WINAPI CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,
LONG lMaximumCount,
LPCTSTR lpName);
信号量在信号数大于0时才为有信号状态。
lInitialCount可以指定初始信号数,lInitialCount取值 [0, lMaximumCount]。
网友评论