muduo是目前在學習過程中遇到的最具有學習意義的網絡庫,下文將分析muduo庫中的基礎設施–Thread和ThreadPool.文中觀點如果部分不符合您的理解,請留言指教,謝謝~ 首先,介紹在多線程編程中不可缺少的同步措施–Mutex和Condition.
Mutexclass MutexLock : boost::noncopyable{ public: MutexLock()//創建一個mutex : holder_(0) { MCHECK(pthread_mutex_init(&mutex_, NULL));//MCHECK是muduo提供的宏定義檢驗函數 } ~MutexLock() { assert(holder_ == 0); MCHECK(pthread_mutex_destroy(&mutex_));//銷毀mutex } // must be called when locked, i.e. for assertion bool isLockedByThisThread() const//是否被當前線程鎖住 { return holder_ == CurrentThread::tid();//防止跨線程調用 } void assertLocked() const { assert(isLockedByThisThread()); } // internal usage void lock() { MCHECK(pthread_mutex_lock(&mutex_));//加鎖 assignHolder();//加鎖時獲得當前線程的線程號,即當前線程擁有這個鎖 } void unlock() { unassignHolder();//表示目前沒有線程擁有這個鎖 MCHECK(pthread_mutex_unlock(&mutex_));//去鎖 } pthread_mutex_t* getPthreadMutex() /* non-const */ { return &mutex_; } PRivate: friend class Condition;//條件變量必須持有了鎖之后才能使用 class UnassignGuard : boost::noncopyable//防止條件變量在占有這個鎖的時候,鎖被銷毀;將holder_設置為0,則既不能被其他線程調用也不能被當前線程銷毀 { public: UnassignGuard(MutexLock& owner) : owner_(owner) { owner_.unassignHolder(); } ~UnassignGuard()//表示鎖被釋放 { owner_.assignHolder(); } private: MutexLock& owner_; }; void unassignHolder() { holder_ = 0; } void assignHolder() { holder_ = CurrentThread::tid(); } pthread_mutex_t mutex_; pid_t holder_;}; }//該類負責管理互斥量的加鎖和解鎖class MutexLockGuard : boost::noncopyable{ public: explicit MutexLockGuard(MutexLock& mutex) : mutex_(mutex)//加鎖 { mutex_.lock(); } ~MutexLockGuard() { mutex_.unlock(); } private: MutexLock& mutex_;};有四種操作互斥鎖的方式:創建,銷毀,加鎖,解鎖。在muduo中,用一個低級的資源管理類MutexLock來實現這四種操作,再用一個較高級的資源管理類MutexLockGuard來管理MutexLock,即用RAII手法對資源進行兩次封裝,防止資源泄漏。
兩個類都具有nocopy的屬性,試想對Mutex的拷貝會在多線程程序中造成什么樣的結果?有至少兩個線程在同一時間擁有對一份資源的使用資格,后果不可設想。
在MutexLock中有一個好玩的私有變量:holder_. 該變量在一個線程對資源加鎖時,將holder_設置為使用資源線程的索引;解鎖時將holder_設置為0。初始化Mutex時將holder_設置為0;銷毀時檢查holder_是否為0。以上四個步驟保證了Mutex在某一個時間段內能被一個線程使用。
MutexLock與Condition是友元關系,具有很強的耦合度。
Conditionclass Condition : boost::noncopyable{//等待時需要占有互斥量,發送信號時不需要占有互斥量 public: explicit Condition(MutexLock& mutex) : mutex_(mutex) { MCHECK(pthread_cond_init(&pcond_, NULL)); }//不拋出異常的構造那函數,以及初始化條件變量 ~Condition()//銷毀條件變量 { MCHECK(pthread_cond_destroy(&pcond_)); } void wait()//使用之前需要占有互斥量 { MutexLock::UnassignGuard ug(mutex_);//目前條件變量所在關聯的Mutex不被當前線程所持有 MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex())); } // returns true if time out, false otherwise. bool waitForSeconds(double seconds);//等待一定時間的wait void notify() { MCHECK(pthread_cond_signal(&pcond_));//通知一條線程 } void notifyAll()//通知所有的線程 { MCHECK(pthread_cond_broadcast(&pcond_)); } private: MutexLock& mutex_; pthread_cond_t pcond_;};條件變量有五種操作方式:創建,銷毀,等待,單一通知,全部通知。
在MutexLock中有一個內部類:UnassignGuard,該類的實例對象在Condition等待時創建,將holder_設置為0;當等待事件結束,又將holder_設置為原值。用MutexLock的析構函數檢查等待事件是否發生在同一個線程中。目的是為了互斥量被意外的銷毀。
Condition類中有一個waitForSecond函數,用于實現pthread_cond_timewait的封裝。 ? ?條件變量在等待時需要持有互斥鎖,但是在通知的時候不需要持有鎖。
新聞熱點
疑難解答