造輪子之線程鎖監控類的封裝

線程鎖監控類的封裝

互斥鎖一個明顯的缺點是它只有兩種狀態:鎖定和非鎖定。而條件變量通過允許線程阻塞和等待另一個線程發送信號的方法彌補了互斥鎖的不足,它常和互斥鎖一起配合使用。使用時,條件變量被用來阻塞一個線程,當條件不滿足時,線程往往解開相應的互斥鎖並等待條件發生變化。一旦其他的某個線程改變了條件變量,他將通知相應的條件變量喚醒一個或多個正被此條件變量阻塞的線程。這些線程將重新鎖定互斥鎖並重新測試條件是否滿足。一般說來,條件變量被用來進行線程間的同步。

實現

/* 通常線程鎖,都通過該類來使用,而不是直接用YR_ThreadMutex、YR_ThreadRecMutex 
 *  
 * 該類將YR_ThreadMutex/YR_ThreadRecMutex 與YR_ThreadCond結合起來; */

template <class T, class P>		//T爲線程鎖類型,P爲線程條件類型
class YR_Monitor
{
public:

    /**
     * @brief 定義鎖控制對象
     */
    typedef YR_LockT<TC_Monitor<T, P> > Lock;
    //typedef YR_TryLockT<TC_Monitor<T, P> > TryLock;

    /**
     * @brief 構造函數
     */
    YR_Monitor() : _nnotify(0)
    {
    }

    /**
     * @brief 析夠
     */
    virtual ~YR_Monitor()
    {
    }

    /**
     * @brief 鎖
     */
    void lock() const
    {
        _mutex.lock();
        _nnotify = 0;
    }

    /**
     * @brief 解鎖, 根據上鎖的次數通知
     */
    void unlock() const
    {
        notifyImpl(_nnotify);
        _mutex.unlock();
    }

    /**
     * @brief 嘗試鎖.
     *
     * @return bool
     */
    bool tryLock() const
    {
        bool result = _mutex.tryLock();
        if(result)
        {
            _nnotify = 0;
        }
        return result;
    }

    /**
     * @brief 等待,當前調用線程在鎖上等待,直到事件通知,
     */
    void wait() const
    {
        notifyImpl(_nnotify);

        try
        {
            _cond.wait(_mutex);
        }
        catch(...)
        {
            _nnotify = 0;
            throw;
        }

        _nnotify = 0;
    }

    /**
     * @brief 等待時間,當前調用線程在鎖上等待,直到超時或有事件通知
     *  
     * @param millsecond 等待時間
     * @return           false:超時了, ture:有事件來了
     */
    bool timedWait(int millsecond) const
    {
        notifyImpl(_nnotify);

        bool rc;

        try
        {
            rc = _cond.timedWait(_mutex, millsecond);
        }
        catch(...)
        {
            _nnotify = 0;
            throw;
        }

        _nnotify = 0;
        return rc;
    }

    /**
     * @brief 通知某一個線程醒來 
     *  
     * 通知等待在該鎖上某一個線程醒過來 ,調用該函數之前必須加鎖, 
     *  
     * 在解鎖的時候才真正通知 
     */
    void notify()
    {
        if(_nnotify != -1)
        {
            ++_nnotify;
        }
    }

    /**
     * @brief 通知等待在該鎖上的所有線程醒過來,
     * 注意調用該函數時必須已經獲得鎖.
     *  
     * 該函數調用前之必須加鎖, 在解鎖的時候才真正通知 
     */
    void notifyAll()
    {
        _nnotify = -1;
    }

protected:

    /**
     * @brief 通知實現. 
     *  
     * @param nnotify 上鎖的次數
     */
    void notifyImpl(int nnotify) const
    {
        if(nnotify != 0)
        {
            if(nnotify == -1)
            {
                _cond.broadcast();
                return;
            }
            else
            {
                while(nnotify > 0)
                {
                    _cond.signal();
                    --nnotify;
                }
            }
        }
    }

private:
    YR_Monitor(const YR_Monitor&);
    void operator=(const YR_Monitor&);

protected:
    mutable int     _nnotify;	//上鎖的次數
    mutable P       _cond;
    T               _mutex;
};

//普通線程鎖
typedef YR_Monitor<YR_ThreadMutex, YR_ThreadCond> YR_ThreadLock;
//循環鎖(一個線程可以加多次鎖)
typedef YR_Monitor<YR_ThreadRecMutex, YR_ThreadCond> YR_ThreadRecLock;
}

這裏互斥鎖和條件變量的配合使用是下面的模式:

pthread_mutex_lock
...
pthread_cond_signal
pthread_mutex_unlock

原因:詳見參考

參考

淺談互斥鎖爲什麼還要和條件變量配合使用

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