天天看點

C++封裝POSIX 線程庫(一)互斥鎖的封裝C++封裝POSIX 線程庫(一)互斥鎖的封裝

C++封裝POSIX 線程庫(一)互斥鎖的封裝

在知乎上有人吐槽說C++11多線程庫做的太複雜,建議自己封裝一蛤,隻要一個下午就搞定了。當然我沒有陳碩老師那麼大學事,花了幾天時間,學習了一下把POSIX Pthread進行簡單的封裝。

1.互斥鎖簡介

互斥鎖主要用于互斥,互斥是一種競争關系,用來保護臨界資源一次隻被一個線程通路。

POSIX Pthread提供下面函數用來操作互斥鎖。

int pthread_mutex_init(pthread_mutex_t  *mutex,  const  pthread_mutexattr_t *mutexattr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//傳回:
//pthread_mutex_init總是傳回0
//其他mutex函數傳回0表示成功,非0的錯誤碼表示失敗
           

由于pthread系列函數傳回成功的時候都是0,是以,我們可以寫一個宏作為一個輕量級的檢查手段,來判斷處理錯誤。

#define CHECK(exp) \
    if(!exp) \
    { \
        fprintf(stderr, "File:%s, Line:%d Exp:[" #exp "] is true, abort.\n",__FILE__, __LINE__); abort();\
    }
           

實際使用的時候隻需:

CHECK(!pthread_mutex_lock(&mutex));
           

2.互斥鎖的封裝

需要考慮以下幾個問題:

a.互斥鎖的初始化與銷毀。

b.互斥鎖的操作:加鎖和釋放鎖。

另外,我們的自己封裝的類不應該有指派和拷貝構造的語義,這一點跟單例模式類似,我們可以使我們的類繼承自boost庫的noncopyable。

//MutexLock.h

#ifndef __MUTEXLOCK_H__
#define __MUTEXLOCK_H__
#include <iostream>
#include <cstdio>
#include <boost/noncopyable.hpp>
#include <pthread.h>
#include <assert.h>

#define CHECK(exp) \
    if(!exp) \
{ \
    fprintf(stderr, "File:%s, Line:%d Exp:[" #exp "] is true, abort.\n",__FILE__, __LINE__); abort();\
}

class MutexLock : public boost::noncopyable
{
    friend class Condition;//條件變量友元聲明
    public:
        MutexLock();
        ~MutexLock();
        void lock();
        void unlock();
        bool isLocking() const 
        {
            return isLocking_;
        }
        pthread_mutex_t *getMutexPtr()
        {
            return &mutex_;
        }
    private:
        void restoreMutexStatus()
        {
            isLocking_=true;
        }
        pthread_mutex_t mutex_;//互斥鎖
        bool isLocking_;
};
#endif
           

這裡完成了Thread 類的聲明,但是這裡還需要一些補充,那就是使用RAII(資源擷取即初始化)技術,對MutexLock初始化和析構進行處理:初始化的時候加鎖,析構的時候解鎖,這就需要我們重新定義一個

class MutexLockGuard

MutexLock

進行操作

//MutexLock.h

class MutexLockGuard:public boost::noncopyable
{
    public:
        MutexLockGuard(MutexLock &mutex):mutex_(mutex){ mutex_.lock();}//構造時加鎖
        ~MutexLockGuard()//析構時解鎖
        {
            mutex_.unlock();
        }

    private:
        MutexLock &mutex_;
};
           

下面就要具體實作幾個函數了,主要是:

pthread_mutex_init()

pthread_mutex_destroy()

pthread_mutex_lock()

pthread_mutex_unlock()

這四個函數的封裝:

//MutexLock.cpp

#include "MutexLock.h"
MutexLock::MutexLock():isLocking_(false)
{
    CHECK(!pthread_mutex_init(&mutex_,NULL));
}
MutexLock::~MutexLock()
{
    assert(!isLocking());
    CHECK(!pthread_mutex_destroy(&mutex_));
}

void MutexLock::lock()
{
    CHECK(!pthread_mutex_lock(&mutex_))//先加鎖再修改狀态,保證以下指派操作的原子性。
    isLocking_=true;
}

void MutexLock::unlock()
{
    isLocking_=false;//先修改狀态在解鎖,保證指派操作的原子性。
    CHECK(!pthread_mutex_unlock(&mutex_));
}
           

封裝以後,我們使用:

對臨界區進行加鎖,而隻要我們控制好

lock

變量的生存期,就能控制臨界區,例如:

int count=;
{
    MutexLockGurad lock(mutex);
    count++;
}//臨界區
//...
//離開lock的作用域,lock作為棧上變量,自動釋放,調用析構函數,同時釋放鎖。
           

3.參考

1.http://www.cnblogs.com/inevermore/p/4008382.html

2.《Linux多線程服務端程式設計—使用muduoC++ 網絡庫》