123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- // Copyright (C) 2001-2003
- // William E. Kempf
- //
- // Permission to use, copy, modify, distribute and sell this software
- // and its documentation for any purpose is hereby granted without fee,
- // provided that the above copyright notice appear in all copies and
- // that both that copyright notice and this permission notice appear
- // in supporting documentation. William E. Kempf makes no representations
- // about the suitability of this software for any purpose.
- // It is provided "as is" without express or implied warranty.
- //////////////////////////////////////////////////////////////////////////////
- //
- // (C) Copyright Ion Gaztanaga 2005-2012. 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)
- //
- // See http://www.boost.org/libs/interprocess for documentation.
- //
- //////////////////////////////////////////////////////////////////////////////
- #ifndef BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP
- #define BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP
- #include <boost/interprocess/detail/config_begin.hpp>
- #include <boost/interprocess/detail/workaround.hpp>
- #include <boost/interprocess/detail/os_thread_functions.hpp>
- #include "boost_interprocess_check.hpp"
- #include <boost/interprocess/sync/scoped_lock.hpp>
- #include <boost/date_time/posix_time/posix_time_types.hpp>
- #include <iostream>
- namespace boost{
- namespace interprocess{
- namespace test {
- boost::posix_time::ptime ptime_delay(int secs)
- {
- return microsec_clock::universal_time() +
- boost::posix_time::time_duration(0, 0, secs);
- }
- template <typename F, typename T>
- class binder
- {
- public:
- binder(const F& f, const T& p)
- : func(f), param(p) { }
- void operator()() const { func(param); }
- private:
- F func;
- T param;
- };
- template <typename F, typename T>
- binder<F, T> bind_function(F func, T param)
- {
- return binder<F, T>(func, param);
- }
- template <class Condition, class Mutex>
- struct condition_test_data
- {
- condition_test_data() : notified(0), awoken(0) { }
- ~condition_test_data()
- {}
- Mutex mutex;
- Condition condition;
- int notified;
- int awoken;
- };
- template <class Condition, class Mutex>
- void condition_test_thread(condition_test_data<Condition, Mutex>* data)
- {
- boost::interprocess::scoped_lock<Mutex>
- lock(data->mutex);
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- while (!(data->notified > 0))
- data->condition.wait(lock);
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- data->awoken++;
- }
- struct cond_predicate
- {
- cond_predicate(int& var, int val) : _var(var), _val(val) { }
- bool operator()() { return _var == _val; }
- int& _var;
- int _val;
- };
- template <class Condition, class Mutex>
- void condition_test_waits(condition_test_data<Condition, Mutex>* data)
- {
- boost::interprocess::scoped_lock<Mutex>
- lock(data->mutex);
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- // Test wait.
- while (data->notified != 1)
- data->condition.wait(lock);
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- BOOST_INTERPROCESS_CHECK(data->notified == 1);
- data->awoken++;
- data->condition.notify_one();
- // Test predicate wait.
- data->condition.wait(lock, cond_predicate(data->notified, 2));
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- BOOST_INTERPROCESS_CHECK(data->notified == 2);
- data->awoken++;
- data->condition.notify_one();
- // Test timed_wait.
- while (data->notified != 3)
- data->condition.timed_wait(lock, ptime_delay(5));
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- BOOST_INTERPROCESS_CHECK(data->notified == 3);
- data->awoken++;
- data->condition.notify_one();
- // Test predicate timed_wait.
- cond_predicate pred(data->notified, 4);
- bool ret = data->condition.timed_wait(lock, ptime_delay(5), pred);
- BOOST_INTERPROCESS_CHECK(ret);(void)ret;
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- BOOST_INTERPROCESS_CHECK(pred());
- BOOST_INTERPROCESS_CHECK(data->notified == 4);
- data->awoken++;
- data->condition.notify_one();
- }
- template <class Condition, class Mutex>
- void do_test_condition_notify_one()
- {
- condition_test_data<Condition, Mutex> data;
- boost::interprocess::ipcdetail::OS_thread_t thread;
- boost::interprocess::ipcdetail::thread_launch(thread, bind_function(&condition_test_thread<Condition, Mutex>, &data));
- //Make sure thread is blocked
- boost::interprocess::ipcdetail::thread_sleep(1000);
- {
- boost::interprocess::scoped_lock<Mutex>
- lock(data.mutex);
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- data.notified++;
- data.condition.notify_one();
- }
- boost::interprocess::ipcdetail::thread_join(thread);
- BOOST_INTERPROCESS_CHECK(data.awoken == 1);
- }
- template <class Condition, class Mutex>
- void do_test_condition_notify_all()
- {
- const int NUMTHREADS = 3;
- boost::interprocess::ipcdetail::OS_thread_t thgroup[NUMTHREADS];
- condition_test_data<Condition, Mutex> data;
- for(int i = 0; i< NUMTHREADS; ++i){
- boost::interprocess::ipcdetail::thread_launch(thgroup[i], bind_function(&condition_test_thread<Condition, Mutex>, &data));
- }
- //Make sure all threads are blocked
- boost::interprocess::ipcdetail::thread_sleep(1000);
- {
- boost::interprocess::scoped_lock<Mutex>
- lock(data.mutex);
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- data.notified++;
- }
- data.condition.notify_all();
- for(int i = 0; i< NUMTHREADS; ++i){
- boost::interprocess::ipcdetail::thread_join(thgroup[i]);
- }
- BOOST_INTERPROCESS_CHECK(data.awoken == NUMTHREADS);
- }
- template <class Condition, class Mutex>
- void do_test_condition_waits()
- {
- condition_test_data<Condition, Mutex> data;
- boost::interprocess::ipcdetail::OS_thread_t thread;
- boost::interprocess::ipcdetail::thread_launch(thread, bind_function(&condition_test_waits<Condition, Mutex>, &data));
- {
- boost::interprocess::scoped_lock<Mutex>
- lock(data.mutex);
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- boost::interprocess::ipcdetail::thread_sleep(1000);
- data.notified++;
- data.condition.notify_one();
- while (data.awoken != 1)
- data.condition.wait(lock);
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- BOOST_INTERPROCESS_CHECK(data.awoken == 1);
- boost::interprocess::ipcdetail::thread_sleep(1000);
- data.notified++;
- data.condition.notify_one();
- while (data.awoken != 2)
- data.condition.wait(lock);
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- BOOST_INTERPROCESS_CHECK(data.awoken == 2);
- boost::interprocess::ipcdetail::thread_sleep(1000);
- data.notified++;
- data.condition.notify_one();
- while (data.awoken != 3)
- data.condition.wait(lock);
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- BOOST_INTERPROCESS_CHECK(data.awoken == 3);
- boost::interprocess::ipcdetail::thread_sleep(1000);
- data.notified++;
- data.condition.notify_one();
- while (data.awoken != 4)
- data.condition.wait(lock);
- BOOST_INTERPROCESS_CHECK(lock ? true : false);
- BOOST_INTERPROCESS_CHECK(data.awoken == 4);
- }
- boost::interprocess::ipcdetail::thread_join(thread);
- BOOST_INTERPROCESS_CHECK(data.awoken == 4);
- }
- /*
- //Message queue simulation test
- template <class Condition>
- inline Condition &cond_empty()
- {
- static Condition cond_empty;
- return cond_empty;
- }
- template <class Condition>
- inline Condition &cond_full()
- {
- static Condition cond_full;
- return cond_full;
- }
- template <class Mutex>
- inline Mutex &mutex()
- {
- static Mutex mut;
- return mut;
- }
- */
- static volatile int count = 0;
- static volatile int waiting_readers = 0;
- static volatile int waiting_writer = 0;
- const int queue_size = 3;
- const int thread_factor = 10;
- const int NumThreads = thread_factor*queue_size;
- //Function that removes items from queue
- template <class Condition, class Mutex>
- struct condition_func
- {
- condition_func(Condition &cond_full, Condition &cond_empty, Mutex &mutex)
- : cond_full_(cond_full), cond_empty_(cond_empty), mutex_(mutex)
- {}
- void operator()()
- {
- boost::interprocess::scoped_lock<Mutex>lock(mutex_);
- while(count == 0){
- ++waiting_readers;
- cond_empty_.wait(lock);
- --waiting_readers;
- }
- --count;
- if(waiting_writer)
- cond_full_.notify_one();
- }
- Condition &cond_full_;
- Condition &cond_empty_;
- Mutex &mutex_;
- };
- //Queue functions
- template <class Condition, class Mutex>
- void do_test_condition_queue_notify_one(void)
- {
- //Force mutex and condition creation
- Condition cond_empty;
- Condition cond_full;
- Mutex mutex;
- //Create threads that will decrease count
- {
- //Initialize counters
- count = 0;
- waiting_readers = 0;
- waiting_writer = 0;
- boost::interprocess::ipcdetail::OS_thread_t thgroup[NumThreads];
- for(int i = 0; i< NumThreads; ++i){
- condition_func<Condition, Mutex> func(cond_full, cond_empty, mutex);
- boost::interprocess::ipcdetail::thread_launch(thgroup[i], func);
- }
- //Add 20 elements one by one in the queue simulation
- //The sender will block if it fills the queue
- for(int i = 0; i < NumThreads; ++i){
- boost::interprocess::scoped_lock<Mutex> lock(mutex);
- while(count == queue_size){
- ++waiting_writer;
- cond_full.wait(lock);
- --waiting_writer;
- }
- count++;
- if(waiting_readers)
- cond_empty.notify_one();
- }
- for(int i = 0; i< NumThreads; ++i){
- boost::interprocess::ipcdetail::thread_join(thgroup[i]);
- }
- BOOST_INTERPROCESS_CHECK(count == 0);
- BOOST_INTERPROCESS_CHECK(waiting_readers == 0);
- BOOST_INTERPROCESS_CHECK(waiting_writer == 0);
- }
- }
- //Queue functions
- template <class Condition, class Mutex>
- void do_test_condition_queue_notify_all(void)
- {
- //Force mutex and condition creation
- Condition cond_empty;
- Condition cond_full;
- Mutex mutex;
- //Create threads that will decrease count
- {
- //Initialize counters
- count = 0;
- waiting_readers = 0;
- waiting_writer = 0;
- boost::interprocess::ipcdetail::OS_thread_t thgroup[NumThreads];
- for(int i = 0; i< NumThreads; ++i){
- condition_func<Condition, Mutex> func(cond_full, cond_empty, mutex);
- boost::interprocess::ipcdetail::thread_launch(thgroup[i], func);
- }
- //Fill queue to the max size and notify all several times
- for(int i = 0; i < NumThreads; ++i){
- boost::interprocess::scoped_lock<Mutex>lock(mutex);
- while(count == queue_size){
- ++waiting_writer;
- cond_full.wait(lock);
- --waiting_writer;
- }
- count++;
- if(waiting_readers)
- cond_empty.notify_all();
- }
- for(int i = 0; i< NumThreads; ++i){
- boost::interprocess::ipcdetail::thread_join(thgroup[i]);
- }
- BOOST_INTERPROCESS_CHECK(count == 0);
- BOOST_INTERPROCESS_CHECK(waiting_readers == 0);
- BOOST_INTERPROCESS_CHECK(waiting_writer == 0);
- }
- }
- template <class Condition, class Mutex>
- bool do_test_condition()
- {
- std::cout << "do_test_condition_notify_one<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
- do_test_condition_notify_one<Condition, Mutex>();
- std::cout << "do_test_condition_notify_all<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
- do_test_condition_notify_all<Condition, Mutex>();
- std::cout << "do_test_condition_waits<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
- do_test_condition_waits<Condition, Mutex>();
- std::cout << "do_test_condition_queue_notify_one<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
- do_test_condition_queue_notify_one<Condition, Mutex>();
- std::cout << "do_test_condition_queue_notify_all<" << typeid(Condition).name() << "," << typeid(Mutex).name() << '\n' << std::endl;
- do_test_condition_queue_notify_all<Condition, Mutex>();
- return true;
- }
- } //namespace test
- } //namespace interprocess{
- } //namespace boost{
- #include <boost/interprocess/detail/config_end.hpp>
- #endif //#ifndef BOOST_INTERPROCESS_CONDITION_TEST_TEMPLATE_HPP
|