| //===----------------------------------------------------------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is dual licensed under the MIT and the University of Illinois Open |
| // Source Licenses. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // Copyright (C) 2013 Vicente J. Botet Escriba |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| |
| // <boost/thread/once.hpp> |
| |
| // struct once_flag; |
| |
| // template<class Callable, class ...Args> |
| // void call_once(once_flag& flag, Callable&& func, Args&&... args); |
| |
| //#define BOOST_THREAD_VERSION 4 |
| #define BOOST_THREAD_USES_MOVE |
| #define BOOST_THREAD_PROVIDES_ONCE_CXX11 |
| |
| #include <boost/thread/once.hpp> |
| #include <boost/thread/thread.hpp> |
| #include <boost/detail/lightweight_test.hpp> |
| |
| #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 |
| #define BOOST_INIT_ONCE_INIT |
| #else |
| #define BOOST_INIT_ONCE_INIT =BOOST_ONCE_INIT |
| #endif |
| |
| typedef boost::chrono::milliseconds ms; |
| |
| boost::once_flag flg0 BOOST_INIT_ONCE_INIT; |
| |
| int init0_called = 0; |
| |
| void init0() |
| { |
| boost::this_thread::sleep_for(ms(250)); |
| ++init0_called; |
| } |
| |
| void f0() |
| { |
| boost::call_once(flg0, init0); |
| } |
| |
| boost::once_flag flg3 BOOST_INIT_ONCE_INIT; |
| |
| int init3_called = 0; |
| int init3_completed = 0; |
| |
| void init3() |
| { |
| ++init3_called; |
| boost::this_thread::sleep_for(ms(250)); |
| if (init3_called == 1) |
| throw 1; |
| ++init3_completed; |
| } |
| |
| void f3() |
| { |
| try |
| { |
| boost::call_once(flg3, init3); |
| } |
| catch (...) |
| { |
| } |
| } |
| |
| struct init1 |
| { |
| static int called; |
| typedef void result_type; |
| |
| void operator()(int i) {called += i;} |
| void operator()(int i) const {called += i;} |
| }; |
| |
| int init1::called = 0; |
| |
| boost::once_flag flg1 BOOST_INIT_ONCE_INIT; |
| |
| void f1() |
| { |
| boost::call_once(flg1, init1(), 1); |
| } |
| |
| boost::once_flag flg1_member BOOST_INIT_ONCE_INIT; |
| |
| struct init1_member |
| { |
| static int called; |
| typedef void result_type; |
| void call(int i) { |
| called += i; |
| } |
| }; |
| int init1_member::called = 0; |
| |
| void f1_member_l() |
| { |
| init1_member o; |
| int i=1; |
| boost::call_once(flg1_member, &init1_member::call, o, i); |
| } |
| void f1_member_r() |
| { |
| init1_member o; |
| boost::call_once(flg1_member, &init1_member::call, o, 1); |
| } |
| struct init2 |
| { |
| static int called; |
| typedef void result_type; |
| |
| void operator()(int i, int j) {called += i + j;} |
| void operator()(int i, int j) const {called += i + j;} |
| }; |
| |
| int init2::called = 0; |
| |
| boost::once_flag flg2 BOOST_INIT_ONCE_INIT; |
| |
| void f2() |
| { |
| boost::call_once(flg2, init2(), 2, 3); |
| boost::call_once(flg2, init2(), 4, 5); |
| } |
| |
| boost::once_flag flg41 BOOST_INIT_ONCE_INIT; |
| boost::once_flag flg42 BOOST_INIT_ONCE_INIT; |
| |
| int init41_called = 0; |
| int init42_called = 0; |
| |
| void init42(); |
| |
| void init41() |
| { |
| boost::this_thread::sleep_for(ms(250)); |
| ++init41_called; |
| } |
| |
| void init42() |
| { |
| boost::this_thread::sleep_for(ms(250)); |
| ++init42_called; |
| } |
| |
| void f41() |
| { |
| boost::call_once(flg41, init41); |
| boost::call_once(flg42, init42); |
| } |
| |
| void f42() |
| { |
| boost::call_once(flg42, init42); |
| boost::call_once(flg41, init41); |
| } |
| |
| class MoveOnly |
| { |
| public: |
| typedef void result_type; |
| |
| BOOST_THREAD_MOVABLE_ONLY(MoveOnly) |
| MoveOnly() |
| { |
| } |
| MoveOnly(BOOST_THREAD_RV_REF(MoveOnly)) |
| {} |
| |
| void operator()(BOOST_THREAD_RV_REF(MoveOnly)) |
| { |
| } |
| void operator()(int) |
| { |
| } |
| void operator()() |
| { |
| } |
| }; |
| |
| |
| struct id_string |
| { |
| static boost::once_flag flag; |
| static void do_init(id_string & ) |
| {} |
| void operator()() |
| { |
| boost::call_once(flag, &id_string::do_init, boost::ref(*this)); |
| } |
| // void operator()(int,int) |
| // { |
| // // This should fail but works with gcc-4.6.3 |
| // //std::bind(&id_string::do_init, *this)(); |
| // std::bind(&id_string::do_init, std::ref(*this))(); |
| // } |
| // void operator()(int) const |
| // { |
| // //std::bind(&id_string::do_init, *this)(); |
| // } |
| }; |
| |
| |
| boost::once_flag id_string::flag BOOST_INIT_ONCE_INIT; |
| |
| int main() |
| { |
| |
| // |
| { |
| id_string id; |
| id(); |
| //id(1,1); |
| } |
| // check basic functionality |
| { |
| boost::thread t0(f0); |
| boost::thread t1(f0); |
| t0.join(); |
| t1.join(); |
| BOOST_TEST(init0_called == 1); |
| } |
| // check basic exception safety |
| { |
| boost::thread t0(f3); |
| boost::thread t1(f3); |
| t0.join(); |
| t1.join(); |
| BOOST_TEST(init3_called == 2); |
| BOOST_TEST(init3_completed == 1); |
| } |
| // check deadlock avoidance |
| { |
| boost::thread t0(f41); |
| boost::thread t1(f42); |
| t0.join(); |
| t1.join(); |
| BOOST_TEST(init41_called == 1); |
| BOOST_TEST(init42_called == 1); |
| } |
| // check functors with 1 arg |
| { |
| boost::thread t0(f1); |
| boost::thread t1(f1); |
| t0.join(); |
| t1.join(); |
| BOOST_TEST(init1::called == 1); |
| } |
| // check functors with 2 args |
| { |
| boost::thread t0(f2); |
| boost::thread t1(f2); |
| t0.join(); |
| t1.join(); |
| BOOST_TEST(init2::called == 5); |
| } |
| |
| // check member function with 1 arg |
| { |
| boost::thread t0(f1_member_l); |
| boost::thread t1(f1_member_r); |
| t0.join(); |
| t1.join(); |
| BOOST_TEST(init1_member::called == 1); |
| } |
| #if defined BOOST_THREAD_PLATFORM_PTHREAD || (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__ > 40600) |
| { |
| boost::once_flag f BOOST_INIT_ONCE_INIT; |
| boost::call_once(f, MoveOnly()); |
| } |
| #endif |
| #if defined BOOST_THREAD_PROVIDES_INVOKE |
| { |
| boost::once_flag f BOOST_INIT_ONCE_INIT; |
| boost::call_once(f, MoveOnly(), 1); |
| } |
| { |
| boost::once_flag f BOOST_INIT_ONCE_INIT; |
| boost::call_once(f, MoveOnly(), MoveOnly()); |
| } |
| #endif // BOOST_THREAD_PLATFORM_PTHREAD |
| return boost::report_errors(); |
| } |
| |
| |