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 // <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