/* 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 "lib/error.hpp" #include "backend/thread-wrapper.hpp" #include "lib/sync.hpp" #include using std::bind; 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) {} }; /** demonstrates how to wait on a simple boolean flag */ class SyncOnBool : public Token, public Sync { protected: volatile 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(); } }; /** this variant demonstrates how to wait on an condition * defined in terms of a (bool) member function */ class SyncOnMemberPredicate : public SyncOnBool { bool checkTheFlag() { return this->got_new_data_; } public: void getIt() { Lock await(this, &SyncOnMemberPredicate::checkTheFlag); sum_ += input_; } }; } // (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, additionally using an embedded condition. We provide * several pre-configured ways of specifying the condition to wait upon. * - check a boolean flag * - evaluate a member function as predicate * * @see SyncLocking_test * @see sync.hpp */ class SyncWaiting_test : public Test { virtual void run (Arg) { SyncOnBool use_sync_var; waitPingPong (use_sync_var); SyncOnMemberPredicate use_member_pred; waitPingPong (use_member_pred); } /** * Helper actually performing the test: * creates two threads and let them block and wait until a start value is given. * When awakened, each thread should add the start value to a common sum field. * @param tok object containing the monitor and condition to be tested. */ void waitPingPong (Token& tok) { typedef backend::ThreadJoinable Thread; Thread ping ("SyncWaiting ping", bind (&Token::getIt, &tok)); Thread pong ("SyncWaiting pong", bind (&Token::getIt, &tok)); CHECK (ping); CHECK (pong); CHECK (0 == tok.result()); usleep (100000); // 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(); CHECK (2*val == tok.result()); } }; /** Register this test class... */ LAUNCHER (SyncWaiting_test, "unit common"); }} // namespace lib::test