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