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 #endif
    157 
    158 int main()
    159 {
    160     // check basic functionality
    161     {
    162         std::thread t0(f0);
    163         std::thread t1(f0);
    164         t0.join();
    165         t1.join();
    166         assert(init0_called == 1);
    167     }
    168     // check basic exception safety
    169     {
    170         std::thread t0(f3);
    171         std::thread t1(f3);
    172         t0.join();
    173         t1.join();
    174         assert(init3_called == 2);
    175         assert(init3_completed == 1);
    176     }
    177     // check deadlock avoidance
    178     {
    179         std::thread t0(f41);
    180         std::thread t1(f42);
    181         t0.join();
    182         t1.join();
    183         assert(init41_called == 1);
    184         assert(init42_called == 1);
    185     }
    186 #ifndef _LIBCPP_HAS_NO_VARIADICS
    187     // check functors with 1 arg
    188     {
    189         std::thread t0(f1);
    190         std::thread t1(f1);
    191         t0.join();
    192         t1.join();
    193         assert(init1::called == 1);
    194     }
    195     // check functors with 2 args
    196     {
    197         std::thread t0(f2);
    198         std::thread t1(f2);
    199         t0.join();
    200         t1.join();
    201         assert(init2::called == 5);
    202     }
    203     {
    204         std::once_flag f;
    205         std::call_once(f, MoveOnly(), MoveOnly());
    206     }
    207 #endif  // _LIBCPP_HAS_NO_VARIADICS
    208 }
    209