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 // <mutex> 11 12 // struct once_flag; 13 14 // template<class Callable, class ...Args> 15 // void call_once(once_flag& flag, Callable func, Args&&... args); 16 17 #include <mutex> 18 #include <thread> 19 #include <cassert> 20 21 typedef std::chrono::milliseconds ms; 22 23 std::once_flag flg0; 24 25 int init0_called = 0; 26 27 void init0() 28 { 29 std::this_thread::sleep_for(ms(250)); 30 ++init0_called; 31 } 32 33 void f0() 34 { 35 std::call_once(flg0, init0); 36 } 37 38 std::once_flag flg3; 39 40 int init3_called = 0; 41 int init3_completed = 0; 42 43 void init3() 44 { 45 ++init3_called; 46 std::this_thread::sleep_for(ms(250)); 47 if (init3_called == 1) 48 throw 1; 49 ++init3_completed; 50 } 51 52 void f3() 53 { 54 try 55 { 56 std::call_once(flg3, init3); 57 } 58 catch (...) 59 { 60 } 61 } 62 63 #ifndef _LIBCPP_HAS_NO_VARIADICS 64 65 struct init1 66 { 67 static int called; 68 69 void operator()(int i) {called += i;} 70 }; 71 72 int init1::called = 0; 73 74 std::once_flag flg1; 75 76 void f1() 77 { 78 std::call_once(flg1, init1(), 1); 79 } 80 81 struct init2 82 { 83 static int called; 84 85 void operator()(int i, int j) const {called += i + j;} 86 }; 87 88 int init2::called = 0; 89 90 std::once_flag flg2; 91 92 void f2() 93 { 94 std::call_once(flg2, init2(), 2, 3); 95 std::call_once(flg2, init2(), 4, 5); 96 } 97 98 #endif // _LIBCPP_HAS_NO_VARIADICS 99 100 std::once_flag flg41; 101 std::once_flag flg42; 102 103 int init41_called = 0; 104 int init42_called = 0; 105 106 void init42(); 107 108 void init41() 109 { 110 std::this_thread::sleep_for(ms(250)); 111 ++init41_called; 112 } 113 114 void init42() 115 { 116 std::this_thread::sleep_for(ms(250)); 117 ++init42_called; 118 } 119 120 void f41() 121 { 122 std::call_once(flg41, init41); 123 std::call_once(flg42, init42); 124 } 125 126 void f42() 127 { 128 std::call_once(flg42, init42); 129 std::call_once(flg41, init41); 130 } 131 132 #ifndef _LIBCPP_HAS_NO_VARIADICS 133 134 class MoveOnly 135 { 136 #if !defined(__clang__) 137 // GCC 4.8 complains about the following being private 138 public: 139 MoveOnly(const MoveOnly&) 140 { 141 } 142 #else 143 MoveOnly(const MoveOnly&); 144 #endif 145 public: 146 MoveOnly() {} 147 MoveOnly(MoveOnly&&) {} 148 149 void operator()(MoveOnly&&) 150 { 151 } 152 }; 153 154 #endif 155 156 int main() 157 { 158 // check basic functionality 159 { 160 std::thread t0(f0); 161 std::thread t1(f0); 162 t0.join(); 163 t1.join(); 164 assert(init0_called == 1); 165 } 166 // check basic exception safety 167 { 168 std::thread t0(f3); 169 std::thread t1(f3); 170 t0.join(); 171 t1.join(); 172 assert(init3_called == 2); 173 assert(init3_completed == 1); 174 } 175 // check deadlock avoidance 176 { 177 std::thread t0(f41); 178 std::thread t1(f42); 179 t0.join(); 180 t1.join(); 181 assert(init41_called == 1); 182 assert(init42_called == 1); 183 } 184 #ifndef _LIBCPP_HAS_NO_VARIADICS 185 // check functors with 1 arg 186 { 187 std::thread t0(f1); 188 std::thread t1(f1); 189 t0.join(); 190 t1.join(); 191 assert(init1::called == 1); 192 } 193 // check functors with 2 args 194 { 195 std::thread t0(f2); 196 std::thread t1(f2); 197 t0.join(); 198 t1.join(); 199 assert(init2::called == 5); 200 } 201 { 202 std::once_flag f; 203 std::call_once(f, MoveOnly(), MoveOnly()); 204 } 205 #endif // _LIBCPP_HAS_NO_VARIADICS 206 } 207