std::lock_guard
std::lock_guard是RAII模板類的簡單實現,功能簡單。
bool try_pop(T& value)
{
std::lock_guard<std::mutex> lk(mut);
if(data_queue.empty())
{
return false;
}
return True; //析構時自動解鎖
}
std::unique_lock
std::unique_lock為鎖管理模板類,是對通用mutex的封裝。std::unique_lock對象以獨占所有權的方式(unique owership)管理mutex對象的上鎖和解鎖操作,即在unique_lock對象的聲明周期內,它所管理的鎖對象會一直保持上鎖狀態;而unique_lock的生命周期結束之后,它所管理的鎖對象會被解鎖。unique_lock具有lock_guard的所有功能,而且更為靈活。雖然二者的對象都不能復制,但是unique_lock可以移動(movable),因此用unique_lock管理互斥對象,可以作為函數的返回值,也可以放到STL的容器中。
std::condition_variable 對象通常使用 std::unique_lock 來等待,如果需要使用另外的 lockable 類型,可以使用std::condition_variable_any類.
void get(int id)
{
std::unique_lock <std::mutex> lk(mtx);
while (!ready) // 如果標志位不為 true, 則等待...
cv.wait(lck); // 當前線程被阻塞, 當全局標志位變為 true 之后,線程被喚醒, 繼續往下執行
}
void put()
{
std::unique_lock <std::mutex> lck(mtx);
ready = true; // 設置全局標志位為 true.
cv.notify_one(); // 喚醒一個線程.
}
關于notify()和notifyAll()
notify()和notifyAll()都是Object對象用于通知處在等待該對象的線程的方法。
void notify(): 喚醒一個正在等待該對象的線程。
void notifyAll(): 喚醒所有正在等待該對象的線程。
兩者的最大區別在于:
notifyAll使所有原來在該對象上等待被notify的線程統統退出wait的狀態,變成等待該對象上的鎖,一旦該對象被解鎖,他們就會去競爭。
notify他只是選擇一個wait狀態線程進行通知,并使它獲得該對象上的鎖,但不驚動其他同樣在等待被該對象notify的線程們,當第一個線程運行完畢以后釋放對象上的鎖,此時如果該對象沒有再次使用notify語句,即便該對象已經空閑,其他wait狀態等待的線程由于沒有得到該對象的通知,繼續處在wait狀態,直到這個對象發出一個notify或notifyAll,它們等待的是被notify或notifyAll,而不是鎖。
std::condition_variable.wait
std::condition_variable提供了兩種 wait() 函數。當前線程調用 wait() 后將被阻塞(此時當前線程應該獲得了鎖(mutex),不妨設獲得鎖 lck),直到另外某個線程調用 notify_* 喚醒了當前線程。
在線程被阻塞時,該函數會自動調用 lck.unlock() 釋放鎖,使得其他被阻塞在鎖競爭上的線程得以繼續執行。另外,一旦當前線程獲得通知(notified,通常是另外某個線程喚醒了當前線程),wait()函數也是自動調用 lck.lock(),使得lck的狀態和 wait 函數被調用時相同。
在第二種情況下(即設置了 Predicate),只有當 pred 條件為false 時調用 wait() 才會阻塞當前線程,并且在收到其他線程的通知后只有當 pred 為 true 時才會被解除阻塞。因此第二種情況類似以下代碼:
data_cond.wait(lk, [this]{
return !data_queue.empty();
})
自制RAII鎖
class MutexLock{
public:
explicit MutexLock(Mutex* mu):_mutex(mu){ lock(_mutex) } //構造時自動上鎖 explicit:顯示調用構造函數
~MutexLock(){ unlock(_mutex) }
private:
Mutex* _mutex; //Mutex 為mutex封裝類
};