blob: ac7b8076956d2bd7dc6eb4c397e2e8eb9596a913 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// 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();
}