spirit/classic/test/grammar_mt_tests.cpp

319 lines
8.1 KiB
C++

/*=============================================================================
Copyright (c) 2003 Martin Wille
http://spirit.sourceforge.net/
Use, modification and distribution is subject to 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)
=============================================================================*/
#include <iostream>
#include <boost/config.hpp>
#include <boost/detail/lightweight_test.hpp>
#if defined(DONT_HAVE_BOOST) || !defined(BOOST_HAS_THREADS) || defined(BOOST_DISABLE_THREADS)
// we end here if we can't do multithreading
static void skipped()
{
std::cout << "skipped\n";
}
int
main()
{
skipped();
return 0;
}
#else
// the real MT stuff
#undef BOOST_SPIRIT_THREADSAFE
#define BOOST_SPIRIT_THREADSAFE
#include <boost/thread/thread.hpp>
#include <boost/spirit/include/classic_grammar.hpp>
#include <boost/spirit/include/classic_rule.hpp>
#include <boost/spirit/include/classic_epsilon.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_types.hpp>
#include <boost/ref.hpp>
static boost::mutex simple_mutex;
static int simple_definition_count = 0;
struct simple : public BOOST_SPIRIT_CLASSIC_NS::grammar<simple>
{
template <typename ScannerT>
struct definition
{
definition(simple const& /*self*/)
{
top = BOOST_SPIRIT_CLASSIC_NS::epsilon_p;
boost::unique_lock<boost::mutex> lock(simple_mutex);
simple_definition_count++;
}
BOOST_SPIRIT_CLASSIC_NS::rule<ScannerT> top;
BOOST_SPIRIT_CLASSIC_NS::rule<ScannerT> const &start() const { return top; }
};
};
struct count_guard
{
count_guard(int &c) : counter(c) {}
~count_guard() { counter = 0; }
private:
int &counter;
};
static void
milli_sleep(unsigned long milliseconds)
{
static long const nanoseconds_per_second = 1000L*1000L*1000L;
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC_);
xt.nsec+=1000*1000*milliseconds;
while (xt.nsec > nanoseconds_per_second)
{
xt.nsec -= nanoseconds_per_second;
xt.sec++;
}
boost::thread::sleep(xt);
}
static void
nap()
{
// this function is called by various threads to ensure
// that thread lifetime actually overlap
milli_sleep(300);
}
template <typename GrammarT>
static void
make_definition(GrammarT &g)
{
char const *text="blah";
BOOST_SPIRIT_CLASSIC_NS::scanner<> s(text, text+4);
g.parse(s);
}
template <typename GrammarT>
static void
make_definition3(GrammarT &g)
{
char const *text="blah";
BOOST_SPIRIT_CLASSIC_NS::scanner<> s(text, text+4);
g.parse(s);
nap();
g.parse(s);
g.parse(s);
}
////////////////////////////////////////////////////////////////////////////////
#define exactly_one_instance_created simple_definition_count == 1
#define exactly_two_instances_created simple_definition_count == 2
#define exactly_four_instances_created simple_definition_count == 4
#define exactly_eight_instances_created simple_definition_count == 8
////////////////////////////////////////////////////////////////////////////////
static void
multiple_attempts_to_instantiate_a_definition_from_a_single_thread()
{
// checks wether exactly one definition per grammar
// object is created
count_guard guard(simple_definition_count);
simple simple1_p;
simple simple2_p;
make_definition(simple1_p);
make_definition(simple1_p);
make_definition(simple1_p);
BOOST_TEST(exactly_one_instance_created);
make_definition(simple2_p);
make_definition(simple2_p);
make_definition(simple2_p);
BOOST_TEST(exactly_two_instances_created);
}
////////////////////////////////////////////////////////////////////////////////
struct single_grammar_object_task
{
void operator()() const
{
make_definition3(simple1_p);
};
simple simple1_p;
};
////////////////////////////////////////////////////////////////////////////////
template <typename T>
class callable_reference_wrapper
: public boost::reference_wrapper<T>
{
public:
explicit callable_reference_wrapper(T& t)
: boost::reference_wrapper<T>(t)
{}
inline void operator()() { this->get().operator()(); }
};
template <typename T>
callable_reference_wrapper<T>
callable_ref(T &t)
{
return callable_reference_wrapper<T>(t);
}
////////////////////////////////////////////////////////////////////////////////
static void
single_local_grammar_object_multiple_threads()
{
// check wether independent definition objects are
// created
count_guard guard(simple_definition_count);
single_grammar_object_task task1, task2, task3, task4;
boost::thread t1(callable_ref(task1));
boost::thread t2(callable_ref(task2));
boost::thread t3(callable_ref(task3));
boost::thread t4(callable_ref(task4));
t1.join();
t2.join();
t3.join();
t4.join();
BOOST_TEST(exactly_four_instances_created);
}
////////////////////////////////////////////////////////////////////////////////
struct two_grammar_objects_task
{
void operator()() const
{
make_definition3(simple1_p);
make_definition3(simple2_p);
};
simple simple1_p;
simple simple2_p;
};
static void
multiple_local_grammar_objects_multiple_threads()
{
// check wether exactly one definition per thread
// and per grammar object is created
count_guard guard(simple_definition_count);
two_grammar_objects_task task1, task2, task3, task4;
boost::thread t1(callable_ref(task1));
boost::thread t2(callable_ref(task2));
boost::thread t3(callable_ref(task3));
boost::thread t4(callable_ref(task4));
t1.join();
t2.join();
t3.join();
t4.join();
BOOST_TEST(exactly_eight_instances_created);
}
////////////////////////////////////////////////////////////////////////////////
static simple global_simple1_p;
struct single_global_grammar_object_task
{
void operator()() const
{
make_definition3(global_simple1_p);
};
};
static void
single_global_grammar_object_multiple_threads()
{
// check wether exactly one definition per thread is
// created
count_guard guard(simple_definition_count);
single_global_grammar_object_task task1, task2, task3, task4;
boost::thread t1(callable_ref(task1));
boost::thread t2(callable_ref(task2));
boost::thread t3(callable_ref(task3));
boost::thread t4(callable_ref(task4));
t1.join();
t2.join();
t3.join();
t4.join();
BOOST_TEST(exactly_four_instances_created);
}
////////////////////////////////////////////////////////////////////////////////
static simple global_simple2_p;
static simple global_simple3_p;
struct multiple_global_grammar_objects_task
{
void operator()() const
{
make_definition3(global_simple2_p);
make_definition3(global_simple3_p);
};
};
static void
multiple_global_grammar_objects_multiple_threads()
{
// check wether exactly one definition per thread
// and per grammar object is created
count_guard guard(simple_definition_count);
multiple_global_grammar_objects_task task1, task2, task3, task4;
boost::thread t1(callable_ref(task1));
boost::thread t2(callable_ref(task2));
boost::thread t3(callable_ref(task3));
boost::thread t4(callable_ref(task4));
t1.join();
t2.join();
t3.join();
t4.join();
BOOST_TEST(exactly_eight_instances_created);
}
////////////////////////////////////////////////////////////////////////////////
int
main()
{
multiple_attempts_to_instantiate_a_definition_from_a_single_thread();
single_local_grammar_object_multiple_threads();
multiple_local_grammar_objects_multiple_threads();
single_global_grammar_object_multiple_threads();
multiple_global_grammar_objects_multiple_threads();
return boost::report_errors();
}
////////////////////////////////////////////////////////////////////////////////
static BOOST_SPIRIT_CLASSIC_NS::parse_info<char const *> pi;
////////////////////////////////////////////////
// These macros are used with BOOST_TEST
#endif // MT mode