C++ 中 std::lock_guard 與 std::unique_lock 的區別

C++ 11 中新增了二個處理 lock 的 wrapper,分別是 std::lock_guard 以及 std::unique_lock,

我們首先來看 C++ 11 對 std::lock_guard 的實作: 


   template<class _Mutex>
	class lock_guard<_Mutex>
	{	// specialization for a single mutex
public:
	typedef _Mutex mutex_type;

	explicit lock_guard(_Mutex& _Mtx)
		: _MyMutex(_Mtx)
		{	// construct and lock
		_MyMutex.lock();
		}

	lock_guard(_Mutex& _Mtx, adopt_lock_t)
		: _MyMutex(_Mtx)
		{	// construct but don't lock
		}

	~lock_guard() _NOEXCEPT
		{	// unlock
		_MyMutex.unlock();
		}

	lock_guard(const lock_guard&) = delete;
	lock_guard& operator=(const lock_guard&) = delete;
private:
	_Mutex& _MyMutex;
	};
    
從程式碼中,可以看到其主要就是在建構子中上鎖,並於解構子中解鎖,
因此 lock_guard 是一個非常輕量的 wrapper,只提供於 block 自動上鎖與解鎖 (避免開發者忘記) 
接著我們再來看 std::unique_lock,根據 cppreference 的描述:
The class unique_lock is a general-purpose mutex ownership wrapper allowing deferred locking, time-constrained attempts at locking, recursive locking, transfer of lock ownership, and use with condition variables.
我們可以從描述中得知 std::unique_lock 除了自動上鎖與解鎖外,
亦提供了一些 wrapper function 讓你在 Timed Lockable 的 mutex 可以呼叫 try_lock_for, try_lock_until 等 function,
另外更重要的是 std::unique_lock 提供了與 std::condition_variable 搭配來 wait 特定 event 完成,
以下是 std::condition_variable 與 std::unique_lock 用於解決 LeetCode 1114. Print in Order 的一個範例
class Foo {
protected:
    int index;
    std::mutex m_mutex;
    std::condition_variable m_cv;
    
    
public:
    Foo() {
        index = 1;
    }

    void first(function<void()> printFirst) {
        {
            std::unique_lock<std::mutex> lock(m_mutex);
            printFirst();
            index = 2;
        }
        m_cv.notify_all();
    }

    void second(function<void()> printSecond) {
        {
            std::unique_lock<std::mutex> lock(m_mutex);
            m_cv.wait(lock, [this]() { return index == 2;});
            printSecond();
            index = 3;
        }
        m_cv.notify_all();
    }

    void third(function<void()> printThird) {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_cv.wait(lock, [this]() { return index == 3;});
        printThird();
    }
};
我們在 second function 內使用 condition_variable 來確保 index 要變成 2 (也就是 first 已先執行),
如果 index 不是 2 的話,就會使用 condition_variable 釋放 lock 並讓當前的 thread wait 直到 first function 的 thread 1 來喚醒自己,
如果 index 已是 2 的話才會往下執行,並於執行完成後喚醒正在等待的 thread 3 (third) ~
以上就是對於 C++ 11 lock_guard 與 unique_lock 的說明 ~ 

留言

這個網誌中的熱門文章

[面試心得] Synology / 群暉 - Product Developr

[面試心得] VICI Holdings / 威旭(高頻交易) - Software Engineer

[面試心得] GoFreight / 聖學科技(Freight Forwarder) - Full-Stack Engineer