1. 程式人生 > >c++ 封裝線程庫 1

c++ 封裝線程庫 1

mes times copy 實現 store oid att ptr amp

1.Pthread條件變量簡介

條件變量也是線程間同步一個重要的內容,如果說互斥是一個種競爭關系,那麽條件變量用於協調線程之間的關系,是一種合作關系。

條件變量的應用很多,例如:BlockingQueueThreadPool等。

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