diff --git a/src/lib/sync.hpp b/src/lib/sync.hpp index 27b72f5c3..d614c96f1 100644 --- a/src/lib/sync.hpp +++ b/src/lib/sync.hpp @@ -147,6 +147,8 @@ namespace lib { struct Monitor { sync::RecMutex mtx_; + sync::Condition cond_; + Monitor() {} ~Monitor() {} diff --git a/tests/lib/sync-waiting-test.cpp b/tests/lib/sync-waiting-test.cpp new file mode 100644 index 000000000..5a0a69a04 --- /dev/null +++ b/tests/lib/sync-waiting-test.cpp @@ -0,0 +1,163 @@ +/* + SyncWaiting(Test) - check the monitor object based wait/notification + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "include/error.hpp" + +#include "lib/sync.hpp" + +#include + +#include + +using std::cout; +using test::Test; + + +namespace lib { + namespace test { + + namespace { // private test classes and data... + + + /** Interface defining the basic interaction pattern for this test */ + class Token + { + public: + + /** blocking concurrent operation */ + virtual void getIt() =0; + + /** start the notification chain */ + virtual void provide (uint val) =0; + + /** harvesting the result...*/ + uint result () { return sum_; } + + + protected: + volatile uint sum_, input_; + + virtual ~Token() {} + + Token() : sum_(0), input_(0) {} + }; + + + class SyncOnBool + : public Token + { + bool got_new_data_; + + public: + SyncOnBool() : got_new_data_ (false) {} + + void getIt() + { + //Lock(*this).wait (got_new_data_); + sum_ += input_; + } + + void provide (uint val) + { + //Lock sync(*this); + input_ = val; + got_new_data_ = true; + //sync.notifyAll(); + } + }; + + } // (End) test classes and data.... + + + + + + + + + + + /**************************************************************************** + * @test concurrent waiting and notification, implemented via object monitor. + * This test covers the second part of the monitor pattern, which builds upon + * the locking part an additionally uses an embedded condition. We provide + * several pre-configured ways of specifying the condition to wait upon. + * + * @see sync.hpp + */ + class SyncWaiting_test : public Test + { + + virtual void + run (Arg) + { + if (!Glib::thread_supported()) + Glib::thread_init(); + + SyncOnBool use_sync_var; + waitPingPong (use_sync_var); + } + + + /** + * Helper actually performing the test: + * creates two threads and let them block and wait cross-wise. + * @param tok object containing the monitor and condition to be tested. + */ + void + waitPingPong (Token& tok) + { + Glib::Thread *ping, *pong; + + ping = Glib::Thread::create(sigc::mem_fun(tok, &Token::getIt), true); + pong = Glib::Thread::create(sigc::mem_fun(tok, &Token::getIt), true); + + ASSERT (ping); + ASSERT (pong); + ASSERT (0 == tok.result()); + + sleep (1); // if the threads don't block correctly, they've missed their chance by now... + + // kick off the notification cascade... + uint val = (rand() % 1000); + tok.provide (val); + + // wait for the two Threads to finish their handshake + pong->join(); + ping->join(); + + ASSERT (2*val == tok.result()); + } + }; + + + + /** Register this test class... */ + LAUNCHER (SyncWaiting_test, "unit common"); + + + + } // namespace test + +} // namespace lumiera