• Class / Function / Type

      std::
    • Header file

      <>
    • Other / All

    最終更新日時(UTC):
    が更新

    履歴 編集

    function template
    <mutex>

    std::lock

    namespace std {
      template <class L1, class L2, class... L3>
      void lock(L1&, L2&, L3&...);
    }
    

    概要

    複数のミューテックスオブジェクトに対してlock操作を行う

    要件

    テンプレートパラメータの型がlock()unlock()try_lock()メンバ関数をサポートしていること

    効果

    各ミューテックスオブジェクトに対して、lock()try_lock()、あるいはunlock()メンバ関数を順次呼び出すことで、デッドロックを引き起こさずに全ミューテックスをロックする。

    いずれかのlock()/try_lock()が例外を送出した場合、以降のlock()/try_lock()呼び出しを行わず、それより前にロック取得したミューテックスオブジェクトに対してunlock()メンバ関数を呼び出す。

    戻り値

    なし

    #include <iostream>
    #include <cassert>
    #include <mutex>
    
    int main()
    {
      std::mutex mtx1;
      std::recursive_mutex mtx2;
    
      // 複数のミューテックスオブジェクトのロック取得を行う
      {
        std::lock(mtx1, mtx2);
    
        mtx1.unlock();
        mtx2.unlock();
      }
    
      // unique_lockに対してロック取得を行う
      {
        std::unique_lock<std::mutex> lk1(mtx1, std::defer_lock);
        std::unique_lock<std::recursive_mutex> lk2(mtx2, std::defer_lock);
    
        std::lock(lk1, lk2);
      }
    
      // 一部のlock()が失敗する場合
      {
        std::unique_lock<std::mutex> lk1(mtx1, std::defer_lock);
        std::unique_lock<std::recursive_mutex> lk2(mtx2, std::defer_lock);
    
        lk2.lock(); // ロック取得済みにしてlock()に渡す
    
        try {
          std::lock(lk1, lk2);
        }
        catch (std::system_error& e) {
          std::cout << e.what() << std::endl;
        }
    
        // lk2が失敗したので、std::lock()内でlk2より前にロック取得が
        // 成功した全てのミューテックスオブジェクトがunlock()される
        assert(!lk1.owns_lock());
    
        // lk2はロック取得済みで渡したので、ロック取得済み状態のまま
        assert(lk2.owns_lock());
      }
    }
    

    出力例

    Resource deadlock avoided
    

    Visual C++ 11.0, 12.0では、このコードは正常に動作せず、1件目のassertで動作を停止してしまう。unique_lock::lock()のバグのためである。

    バージョン

    言語

    • C++11

    処理系

    参照