天天看點

優雅的讓一個類線上程安全和線程非安全間切換

一個良好的多線程庫,不應當一刀切的全加鎖。因為有些時候,雖然是多線程環境,但可能依照設計一個類隻會被一個線程操作,這個時候加鎖是多餘的,純浪費性能,但另一些場景又需要它是線程安全的。

假設有一個類X:

class X

{

public:

    void xoo();

};

這裡總結幾個常見的做法:

1.本身不加鎖,由調用者來加鎖,壞處是如果多數場景都是加鎖的,由會産生重複代碼

class Z

    void zoo()

    {

        LockHelper<CLock> lh(_lock); // 調用者Z來加鎖

        _x.xoo();

    };

private:

    CLock _lock;

    X _x;

2.類的實作中,加if判斷

    X(bool is_threadsafe)

     :_is_threadsafe(is_threadsafe)

    }

    void xoo()

        if (_is_threadsafe)

        {

            // 根據條件加鎖

            _lock.lock();

        }

        。。。。。。

            _lock.unlock();

    bool _is_threadsafe;

3.分成兩個類,第一個類是無鎖的,第二個類通過聚合第一個類,并用鎖包裝一下

class RawX

        // RawX總是不加鎖

class SafeX

        LockHelper<CLock> lh(_lock); // 總是加鎖

        _raw_x.xoo();

    RawX _raw_x;

下面提出一種在mooon中使用的相對更優雅的方法,引用一個空鎖類CNullLock,它僅提供鎖的接口,加鎖和解鎖函數體都是空的:

class CNullLock

    void lock()

    void unlock()

接下來看新的X的實作,需要将它變成一個模闆類:

template <class Lock>

        LockHelper<CLock> lh(_lock); // 這裡并不一定真是加鎖

如果需要X是線程安全的,可以這樣使用:

X<CLock> x;

如果不需要X是線程安全的,則可以如下使用:

X<CNullLock> x;

這樣的一個X,看起來是不是相對優雅得體些了?

繼續閱讀