poco Mutex(互斥量)

作用:
互斥量用於線程間同步。實際上就是鎖住某部分指令。
linux 底層的 api 互斥量使用還是很麻煩的。pthread_mutex_init()
pthread_mutex_lock() pthread_mutex_destory()
下面是 Poco 裏關於鎖的一些實現。

這裏寫圖片描述
要看 Poco::Mutex 所以我們應該去看基類 Poco::MutexImpl 類的實現。


class Foundation_API MutexImpl
{
protected:
    MutexImpl();
    MutexImpl(bool fast);
    ~MutexImpl();
    void lockImpl();
    bool tryLockImpl();
    bool tryLockImpl(long milliseconds);
    void unlockImpl();

private:
    pthread_mutex_t _mutex;
};

MutexImpl () 默認構造函數主要是執行鎖的初始化,初始化爲可以遞歸的鎖。即同一個線程可以多次進行鎖。

    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&_mutex, &attr);
    pthread_mutexattr_destroy(&attr);

MutexImpl( bool fast ) 帶參數構造函數 主要在設置遞歸鎖的時候判斷標誌位 fast.如果 fast 爲true 那麼爲不可遞歸的互斥量。也就是下面將要講到的 Poco::FastMutex ,如果爲 false 那麼就是可以遞歸的互斥量也就是 Poco::Mutex。

    pthread_mutexattr_settype(&attr, fast ? PTHREAD_MUTEX_NORMAL : PTHREAD_MUTEX_RECURSIVE);

主要的方法:

    void lockImpl();//加鎖
    bool tryLockImpl();//調用tryLock 函數。成功返回 true,失敗返回 false.
    bool tryLockImpl(long milliseconds);//調用pthread_mutex_timeLock() 函數。成功返回 true,失敗返回 false.
    void unlockImpl();//解鎖。

Poco::Mutex 私有繼承 MutexImpl

class Foundation_API Mutex: private MutexImpl

Poco::Mutex 創建的是默認的可以遞歸的互斥量(需要注意的是同一線成可以多次鎖,但是要多次解鎖,不同線程不行)。

    void lock();
    void lock(long milliseconds);
    bool tryLock();
    bool tryLock(long milliseconds);//等待獲取鎖,到達時間沒有獲取返回 false。
    void unlock();

Poco 最簡單的互斥量使用,兩個線程,每個線程都先獲取鎖 2S 之後釋放鎖。

#include <iostream>
#include <Poco/Mutex.h>
#include <Poco/Thread.h>
#include <unistd.h>

class Worker : public Poco::Runnable
{
public:
    Worker( Poco::Mutex& mtx ):
        _mtx(mtx)
    {
    }

    void run( )
    {
        //獲取鎖
        _mtx.lock();
        std::cout << Poco::Thread::currentTid() << "   get mtx" << std::endl;
        sleep( 2 );
        _mtx.unlock();
    }

private:
    Poco::Mutex& _mtx;
};


int main( )
{
    Poco::Mutex mtx;

    Poco::Thread th1,th2;
    Worker w1( mtx );
    Worker w2( mtx );

    th1.start( w1 );
    th2.start( w2 );

    th1.join();
    th2.join();
}

可以一個線程先獲取了鎖,等了兩秒之後先獲取鎖的線程釋放了鎖,第二個線程才能獲取鎖。

Poco::FastMutex 繼承於 FastMutexImpl
FastMutexImpl 繼承於 Poco::MutexImpl

FastMutexImpl 的構造函數指定調用 MutexImpl( true ) 夠造一個不能多次鎖的普通鎖對象。

所以 FastMutex 的功能和 Mutex 的功能一樣只是,不能多次鎖,否則造成死鎖。

在 Poco 互斥量裏有一個不得不說的類它就是 Poco::ScopedLock。是一個模板類。它只有3 個 public 方法。
兩個構造函數,第一個ScopedLock(M& mutex)是調用傳進來的 互斥量的 lock() 方法。第二個ScopedLock(M& mutex, long milliseconds) 是調用傳撿來的互斥量的 lock( milliseconds ) 方法。

一個析構函數調用 互斥量的 unlock() 方法。所以使用 Poco::ScopeLock 類的作用是在構造的時候會自動獲取鎖,在函數退出的時候自動釋放鎖。
ScopeLock 在Mutex 和 FastMutex 都有實例化。所以使用的鎖如果是
Mutex 類型的那麼只要
Poco::Mutex::ScopedLock s( _mtx );
Poco::FastMutex::ScopeLock( _mtx );

template <class M>
class ScopedLock
{
public:
    explicit ScopedLock(M& mutex): _mutex(mutex)
    {
        _mutex.lock();
    }

    ScopedLock(M& mutex, long milliseconds): _mutex(mutex)
    {
        _mutex.lock(milliseconds);
    }

    ~ScopedLock()
    {
        try
        {
            _mutex.unlock();
        }
        catch (...)
        {
            poco_unexpected();
        }
    }

下面還是剛剛那個例子。現在改成使用 ScopeLock 來實現。

#include <iostream>
#include <Poco/Mutex.h>
#include <Poco/Thread.h>
#include <unistd.h>

class Worker : public Poco::Runnable
{
public:
    Worker( Poco::Mutex& mtx ):
        _mtx(mtx)
    {
    }

    void run( )
    {
        //獲取鎖
        Poco::Mutex::ScopedLock s( _mtx );
      std::cout << Poco::Thread::currentTid() << "   get mtx" << std::endl;
        sleep( 2 );
    }

private:
    Poco::Mutex& _mtx;
};


int main( )
{
    Poco::Mutex mtx;

    Poco::Thread th1,th2;
    Worker w1( mtx );
    Worker w2( mtx );

    th1.start( w1 );
    th2.start( w2 );

    th1.join();
    th2.join();
}

從上面代碼可以看出來。使用 ScopeLock 可以不需要關心釋放鎖。所以推薦使用 ScopeLock.

既然有 ScopeLock() 類可以自動幫我我獲取鎖,退出函數幫我們釋放鎖。那麼有沒有哪個類,可以幫我們在自動釋放鎖,退出函數的時候自動加鎖。ScopedUnlock 類就可以實現這樣的功能。

應用場景:
比如說當一個線程(A)獲取了鎖需要從數據庫鏈接池獲取一個數據鏈接,但是此時沒有,那麼並且需要等到另外的線程(B,C,D)的釋放鏈接信號才能繼續執行。但線程B 把鏈接放回池需要獲取鎖,這個時候那應該就是 線程 A 在進入阻塞等待之前先釋放鎖,然後 B 獲取了鎖,把鏈接放回去,才發送信號。A 接收到信號之後,激活繼續向下 運行,在退出函數的時候重新獲取鎖。
例子先不寫了。下一篇的 Poco::Event 線程間通信可在細述。

轉載請註明出處
http://blog.csdn.net/yuhaiyang457288/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章