ミューテックスクラスのオブジェクトを、スコープ内で確実にロック/アンロックするためのクラスとして、std::lock_guardとstd::unique_lockという2つのクラスが提供されています。
std::lock_guardは単純な用途のためのクラスなのでムーブできませんが、std::unique_lockはムーブできます。
たとえば、ロック済みミューテックスを返す関数をstd::unique_lockで作ると、受け取った側が使い終わったら自動的にアンロックしてくれます。
#include <iostream> #include <mutex> #include <thread> class X { int value_ = 0; mutable std::mutex mtx_; public: void add_value() { std::unique_lock<std::mutex> lk = get_locked_mutex(); ++value_; } // ここでアンロックされる int get() const { std::unique_lock<std::mutex> lk = get_locked_mutex(); return value_; } private: std::unique_lock<std::mutex> get_locked_mutex() const { return std::unique_lock<std::mutex>(mtx_); // ロックして返す } }; int main() { X x; std::thread t1([&] { x.add_value(); }); std::thread t2([&] { x.add_value(); }); t1.join(); t2.join(); std::cout << x.get() << std::endl; }
2
関数の引数としてロック済みミューテックスを渡すと、渡された側のスコープ終了時に自動的にアンロックされます。
#include <iostream> #include <mutex> #include <thread> #include <atomic> class spinlock { private: typedef enum {Locked, Unlocked} LockState; std::atomic<LockState> state_; public: spinlock() : state_(Unlocked) {} void lock() { // 現在の状態をLockedと入れ替える while (state_.exchange(Locked, std::memory_order_acquire) == Locked) { // busy-wait...アンロックされるまで待機 } std::cout << "lock" << std::endl; } void unlock() { // 値をUnlockedに更新 state_.store(Unlocked, std::memory_order_release); std::cout << "unlock" << std::endl; } }; class X { int value_ = 0; mutable spinlock mtx_; public: void add_value() { add_value_impl(get_locked_mutex()); // ロック済みミューテックスをムーブ } int get() const { std::unique_lock<spinlock> lk = get_locked_mutex(); return value_; } private: void add_value_impl(std::unique_lock<spinlock>) { ++value_; std::cout << "add valued" << std::endl; } // ここでアンロックされる std::unique_lock<spinlock> get_locked_mutex() const { return std::unique_lock<spinlock>(mtx_); // ロックして返す } }; int main() { X x; std::thread t1([&] { x.add_value(); }); std::thread t2([&] { x.add_value(); }); t1.join(); t2.join(); std::cout << x.get() << std::endl; }
lock add valued unlock lock add valued unlock lock unlock 2
参照:
std::unique_lock - cpprefjp
std::lock_guard - cpprefjp
Thread-Safe Copy and Move Constructors