Home | History | Annotate | Download | only in thread.lock.scoped
      1 //===----------------------------------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // UNSUPPORTED: libcpp-has-no-threads
     11 // UNSUPPORTED: c++98, c++03, c++11, c++14
     12 
     13 // <mutex>
     14 
     15 // template <class ...Mutex> class scoped_lock;
     16 
     17 // explicit scoped_lock(mutex_type& m);
     18 
     19 #include <mutex>
     20 #include <cassert>
     21 #include "test_macros.h"
     22 
     23 struct TestMutex {
     24     bool locked = false;
     25     TestMutex() = default;
     26     ~TestMutex() { assert(!locked); }
     27 
     28     void lock() { assert(!locked); locked = true; }
     29     bool try_lock() { if (locked) return false; locked = true; return true; }
     30     void unlock() { assert(locked); locked = false; }
     31 
     32     TestMutex(TestMutex const&) = delete;
     33     TestMutex& operator=(TestMutex const&) = delete;
     34 };
     35 
     36 #if !defined(TEST_HAS_NO_EXCEPTIONS)
     37 struct TestMutexThrows {
     38     bool locked = false;
     39     bool throws_on_lock = false;
     40 
     41     TestMutexThrows() = default;
     42     ~TestMutexThrows() { assert(!locked); }
     43 
     44     void lock() {
     45         assert(!locked);
     46         if (throws_on_lock) {
     47             throw 42;
     48         }
     49         locked = true;
     50     }
     51 
     52     bool try_lock() {
     53         if (locked) return false;
     54         lock();
     55         return true;
     56     }
     57 
     58     void unlock() { assert(locked); locked = false; }
     59 
     60     TestMutexThrows(TestMutexThrows const&) = delete;
     61     TestMutexThrows& operator=(TestMutexThrows const&) = delete;
     62 };
     63 #endif // !defined(TEST_HAS_NO_EXCEPTIONS)
     64 
     65 int main()
     66 {
     67     {
     68         using LG = std::scoped_lock<>;
     69         LG lg;
     70     }
     71     {
     72         using LG = std::scoped_lock<TestMutex>;
     73         TestMutex m1;
     74         {
     75             LG lg(m1);
     76             assert(m1.locked);
     77         }
     78         assert(!m1.locked);
     79     }
     80     {
     81         using LG = std::scoped_lock<TestMutex, TestMutex>;
     82         TestMutex m1, m2;
     83         {
     84             LG lg(m1, m2);
     85             assert(m1.locked && m2.locked);
     86         }
     87         assert(!m1.locked && !m2.locked);
     88     }
     89     {
     90         using LG = std::scoped_lock<TestMutex, TestMutex, TestMutex>;
     91         TestMutex m1, m2, m3;
     92         {
     93             LG lg(m1, m2, m3);
     94             assert(m1.locked && m2.locked && m3.locked);
     95         }
     96         assert(!m1.locked && !m2.locked && !m3.locked);
     97     }
     98 #if !defined(TEST_HAS_NO_EXCEPTIONS)
     99     {
    100         using MT = TestMutexThrows;
    101         using LG = std::scoped_lock<MT>;
    102         MT m1;
    103         m1.throws_on_lock = true;
    104         try {
    105             LG lg(m1);
    106             assert(false);
    107         } catch (int) {}
    108         assert(!m1.locked);
    109     }
    110     {
    111         using MT = TestMutexThrows;
    112         using LG = std::scoped_lock<MT, MT>;
    113         MT m1, m2;
    114         m1.throws_on_lock = true;
    115         try {
    116             LG lg(m1, m2);
    117             assert(false);
    118         } catch (int) {}
    119         assert(!m1.locked && !m2.locked);
    120     }
    121     {
    122         using MT = TestMutexThrows;
    123         using LG = std::scoped_lock<MT, MT, MT>;
    124         MT m1, m2, m3;
    125         m2.throws_on_lock = true;
    126         try {
    127             LG lg(m1, m2, m3);
    128             assert(false);
    129         } catch (int) {}
    130         assert(!m1.locked && !m2.locked && !m3.locked);
    131     }
    132 #endif
    133 
    134 #ifdef __cpp_deduction_guides
    135     {
    136     TestMutex m1, m2, m3;
    137         {
    138         std::scoped_lock sl{};
    139         static_assert((std::is_same<decltype(sl), std::scoped_lock<>>::value), "" );
    140         }
    141         {
    142         std::scoped_lock sl{m1};
    143         static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1)>>::value), "" );
    144         }
    145         {
    146         std::scoped_lock sl{m1, m2};
    147         static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1), decltype(m2)>>::value), "" );
    148         }
    149         {
    150         std::scoped_lock sl{m1, m2, m3};
    151         static_assert((std::is_same<decltype(sl), std::scoped_lock<decltype(m1), decltype(m2), decltype(m3)>>::value), "" );
    152         }
    153     }
    154 #endif
    155 }
    156