ミューテックスを自動的にアンロックするためのstd::lock_guardクラスとstd::unique_lockクラスでは、そのコンストラクタでいくつかのロック方法を提供しています。
1. 何も指定しない
まず、何も指定しない場合。この場合、ミューテックスクラスのlock()メンバ関数を使用してロックの取得が行われます。これはstd::lock_guardとstd::unique_lockの両方でサポートされています。
#include <iostream> #include <mutex> int main() { std::mutex mtx; { std::unique_lock<std::mutex> lk(mtx); // lock()が呼ばれる // 共有リソースにアクセス... } // unlock()が呼ばれる }
2. defer_lock
std::defer_lockを指定した場合、すぐにはロックを取得せず、あとから自分でlock()、try_lock()、try_lock_for()、try_lock_until()を好きに呼び出せます。これはstd::unique_lockでのみサポートされています。
コンストラクタの呼び出し時点では、ロック取得中かどうかを示すowns_lock()メンバ関数の結果はfalseとなります。
#include <iostream> #include <mutex> int main() { std::mutex mtx; { std::unique_lock<std::mutex> lk(mtx, std::defer_lock); // lock()が呼ばれない mtx.lock(); // ロックを取得する // 共有リソースにアクセス... } // unlock()が呼ばれる }
3. try_to_lock
std::try_to_lockを指定した場合、コンストラクタ内ではlock()の代わりにtry_lock()が実行されます。ロックの取得に失敗した場合はowns_lock() == falseになるので、状況によってエラー報告やロック取得のリトライをします。これはstd::unique_lockでのみサポートされます。
#include <iostream> #include <mutex> #include <stdexcept> int main() { std::mutex mtx; { std::unique_lock<std::mutex> lk(mtx, std::try_to_lock); // try_lock()が呼ばれる if (!lk.owns_lock()) { throw std::runtime_error("ロックの取得に失敗!"); } // 共有リソースにアクセス... } // unlock()が呼ばれる }
4. adopt_lock
std::adopt_lockを指定した場合、そのコンストラクタは「ロック済みミューテックス」を受け取り、ロック取得のための関数は呼ばれません。std::defer_lockとの違いは、std::defer_lockが「ロック取得していない(owns_lock() == false)」状態になるのに対し、std::adopt_lockは「ロック取得している(owns_lock() == true)」になる、ということです。これはstd::lock_guardとstd::unique_lockの両方でサポートされます。
#include <iostream> #include <mutex> int main() { std::mutex mtx; { mtx.lock(); // 事前にロックを取得する std::unique_lock<std::mutex> lk(mtx, std::adopt_lock); // コンストラクタではロック取得しない // 共有リソースにアクセス... } // unlock()が呼ばれる }
参照:
std::defer_lock - cpprefjp
std::try_to_lock - cpprefjp
std::adopt_lock - cpprefjp