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 MoveOnly(const MoveOnly&); 137 public: 138 MoveOnly() {} 139 MoveOnly(MoveOnly&&) {} 140 141 void operator()(MoveOnly&&) 142 { 143 } 144 }; 145 146 #endif 147 148 int main() 149 { 150 // check basic functionality 151 { 152 std::thread t0(f0); 153 std::thread t1(f0); 154 t0.join(); 155 t1.join(); 156 assert(init0_called == 1); 157 } 158 // check basic exception safety 159 { 160 std::thread t0(f3); 161 std::thread t1(f3); 162 t0.join(); 163 t1.join(); 164 assert(init3_called == 2); 165 assert(init3_completed == 1); 166 } 167 // check deadlock avoidance 168 { 169 std::thread t0(f41); 170 std::thread t1(f42); 171 t0.join(); 172 t1.join(); 173 assert(init41_called == 1); 174 assert(init42_called == 1); 175 } 176 #ifndef _LIBCPP_HAS_NO_VARIADICS 177 // check functors with 1 arg 178 { 179 std::thread t0(f1); 180 std::thread t1(f1); 181 t0.join(); 182 t1.join(); 183 assert(init1::called == 1); 184 } 185 // check functors with 2 args 186 { 187 std::thread t0(f2); 188 std::thread t1(f2); 189 t0.join(); 190 t1.join(); 191 assert(init2::called == 5); 192 } 193 { 194 std::once_flag f; 195 std::call_once(f, MoveOnly(), MoveOnly()); 196 } 197 #endif // _LIBCPP_HAS_NO_VARIADICS 198 } 199