c++ 封裝線程庫 1
1.Pthread條件變量簡介
條件變量也是線程間同步一個重要的內容,如果說互斥是一個種競爭關系,那麽條件變量用於協調線程之間的關系,是一種合作關系。
條件變量的應用很多,例如:BlockingQueue
,ThreadPool
等。
2. 條件變量的封裝
其實就是對pthread_cond_t
和相關函數的封裝:
#include <pthread.h> pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//靜態初始化 int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);//動態初始化int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); int pthread_cond_destroy(pthread_cond_t *cond);
另外,我們在調用pthread_cond_wait的時候,必須先加鎖,需要用到之前MutexLock
的私用成員函數,這裏已經在MutexLock.h
中將class Condition
設定為了MutexLock
的一個友元。
//Condition.h #ifndef __CONDITION_H__ #define __CONDITION_H__ #include "MutexLock.h" #include <pthread.h> #include <boost/noncopyable.hpp> #include <assert.h> class MutexLock;class Condition { public: Condition(MutexLock &mutex); ~Condition(); void wait();//封裝pthread_cond_wait void notify();//封裝pthread_cond_signal void notifyAll();//封裝pthread_cond_broadcast private: pthread_cond_t cond_; MutexLock &mutex_; }; #endi#include "Condition.#include "MutexLock.h"#include <assert.h>
Condition::Condition(MutexLock &mutex):mutex_(mutex)
{
CHECK(!pthread_cond_init(&cond_, NULL));//條件變量初始化
}
Condition::~Condition()
{
CHECK(!pthread_cond_destroy(&cond_));//析構操作
}
void Condition::wait()
{
assert(mutex_.isLocking());//wait前必須上鎖 assert函數就是用來調試的 assert(exp) 若exp的表達式為假 則程序不執行結束報錯 為真則什麽也不做!!
CHECK(!pthread_cond_wait(&cond_, mutex_.getMutexPtr()));
//pthread_cond_wait 阻塞時釋放鎖,返回時會自動加鎖
mutex_.restoreMutexStatus(); //還原狀態
}
void Condition::notify()
{
CHECK(!pthread_cond_signal(&cond_));//通知等待線程隊列中的線程
}
void Condition::notifyAll()
{
CHECK(!pthread_cond_broadcast(&cond_));//通知所有等待線程
}
註意學習下知識點:!!!
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
等待條件有兩種方式:無條件等待pthread_cond_wait()和計時等待pthread_cond_timedwait(),其中計時等待方式如果在給定時刻前條件沒有滿足,則返回ETIMEOUT,結束等待,
其中abstime以與time()系統調用相同意義的絕對時間形式出現,0表示格林尼治時間1970年1月1日0時0分0秒。
無論哪種等待方式,都必須和一個互斥鎖配合,以防止多個線程同時請求pthread_cond_wait()(或pthread_cond_timedwait(),下同)的競爭條件(Race Condition)。
mutex互斥鎖必須是普通鎖(PTHREAD_MUTEX_TIMED_NP)或者適應鎖(PTHREAD_MUTEX_ADAPTIVE_NP),且在調用pthread_cond_wait()前必須由本線程加鎖(pthread_mutex_lock()),
而在更新條件等待隊列以前,mutex保持鎖定狀態,並在線程掛起進入等待前解鎖。
在條件滿足從而離開pthread_cond_wait()之前,mutex將被重新加鎖,以與進入pthread_cond_wait()前的加鎖動作對應。
激發條件有兩種形式,pthread_cond_signal()激活一個等待該條件的線程,存在多個等待線程時按入隊順序激活其中一個; 而pthread_cond_broadcast()則激活所有等待線程。
=========================================================
在網上看到一個名詞“驚群效應”,意思就是說broadcast
使用不當,當喚醒所有線程而只有一個線程能夠拿到資源,所以關於broadcast
還是要慎用。
關於封裝條件變量的一般使用,假設我們要實現簡單的容量無限的BlockingQueue
,可以這樣寫: BlockingQueue就是阻塞隊列 經典到就是生產者消費者模型的實現
MutexLock mutex;
Condition cond(mutex);
std::deque<int> queue;
int dequeue()//出列
{
MutexLockGurad lock(mutex);
while(queue.empty())
{
cond.wait();//這一步會釋放mutex並進入等待,這兩個操作是原子的
//wait()返回後,會自動重新加鎖 這個wait就是condition類中封裝的 pthread_cond_wait函數
}
assert(!queue.empty());
int top = queue.front();
queue.pop_front();
return top;
}
void enqueue(int x )//入隊
{
MutexLockGurad(mutex);
queue.push_back(x);
cond.notify();//這句也可以移出臨界區 ??????不是特別明白
}
c++ 封裝線程庫 1