windows线程同步

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.

Paste_Image.png

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]。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容