1. 程式人生 > 其它 >C++實現訊號量

C++實現訊號量

背景
實現
程式碼toc

背景

訊號量與條件變數差異對比

  • 訊號量存在一個計數,可以反映出當前阻塞在wait上的執行緒數(值小於0),或下次wait不會阻塞的執行緒數;條件變數沒有相應計數
  • 訊號量僅能遞增或遞減計數,訊號量每次遞增只能喚醒一個阻塞執行緒;條件變數存在廣播操作,能一次性喚醒所有阻塞執行緒
  • 訊號量計數可以被初始化為大於0的數n,代表可訪問資源個數,在後續訪問時wait時,n個執行緒均不會阻塞,可同時訪問資源;條件變數初始化後,執行wait的執行緒將全部阻塞,直到收到通知
  • 訊號量遞增一次,便會多一個wait不阻塞的執行緒數(不存在阻塞執行緒時);對於條件變數,當沒有執行緒阻塞在wait時,發出的喚醒訊號將被丟棄,導致先發出喚醒訊號,隨後wait將仍被阻塞,即所謂的喚醒丟失
  • 訊號量不存在虛假喚醒問題;條件變數存在虛假喚醒
  • 訊號量可單獨使用;條件變數必須需配合mutex一起使用

C++標準庫僅有條件變數,而沒有訊號量,下面實現一個跨平臺訊號量

實現

訊號量最基本的操作有三個

  • 初始化決定了wait後可立即執行執行緒數
  • 遞減操作SemWait,該操作使訊號量減1,如果減1後變為負數,執行緒會阻塞在SemWait上,否則繼續執行
  • 遞增操作SemSignal,該操作使訊號量加1,如果加1後大於等於0,阻塞在SemWait上的執行緒被喚醒

程式碼

#pragma once
#include <mutex>
#include <condition_variable>

class Semaphore final{
public:
    explicit Semaphore(int iCount = 0);
    ~Semaphore();

    void Signal();
    void Wait();
    int GetValue();

    Semaphore(const Semaphore& rhs) = delete;
    Semaphore(Semaphore&& rhs) = delete;
    Semaphore& operator=(const Semaphore& rhs) = delete;
    Semaphore& operator=(Semaphore&& rhs) = delete;

private:
    std::mutex m_mLock;
    std::condition_variable m_cConditionVariable;
    int m_iCount;
};
#include "Semaphore.h"

Semaphore::Semaphore(int iCount) : m_iCount(iCount){
}

Semaphore::~Semaphore(){
}

void Semaphore::Signal(){
    std::unique_lock<std::mutex> lock(m_mLock);
    if(++m_iCount >= 0){
        m_cConditionVariable.notify_one();
    }
}

void Semaphore::Wait(){
    std::unique_lock<std::mutex> lock(m_mLock);
    --m_iCount;
    m_cConditionVariable.wait(lock, [this] { return m_iCount >= 0; });
}

int Semaphore::GetValue(){
    std::unique_lock<std::mutex> lock(m_mLock);
    return m_iCount;
}


來自為知筆記(Wiz)

原創不易,轉載請註明出處,謝謝