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