Commit 9fddfb4c authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[ADD] - One Shot conditions avoiding endless wait of threads when a condition was fired already

parent 7721fab4
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include "WConditionOneShot.h"
WConditionOneShot::WConditionOneShot()
: WCondition()
{
// initialize members
m_lock = boost::unique_lock<boost::shared_mutex>( m_mutex );
}
WConditionOneShot::~WConditionOneShot()
{
// cleanup
try
{
m_lock.unlock();
}
catch ( const boost::lock_error &e )
{
// ignore this particular error since it is thrown when the lock is not locked anymore
}
}
void WConditionOneShot::wait()
{
// now we wait until the write lock is released and we can get a read lock
boost::shared_lock<boost::shared_mutex> slock = boost::shared_lock<boost::shared_mutex>( m_mutex );
slock.unlock();
}
void WConditionOneShot::notify()
{
// release the write lock to allow waiting threads to achieve read lock
m_lock.unlock();
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WCONDITIONONESHOT_H
#define WCONDITIONONESHOT_H
#include <boost/thread.hpp>
#include "WCondition.h"
/**
* Implements a WCondition, but can be fired only ONCE. This is useful if you want to have a thread waiting for a condition but
* you can not assure that the thread already waits when you set the condition. This would cause the thread to wait endlessly
* because he does not know that you already fired it. Implementation is simple. The constructor uses a unique lock (write lock)
* on a mutex. All waiting threads try to get a read lock which is not possible as long it is write-locked. The notify method
* releases the write lock and all waiting threads can continue.
*/
class WConditionOneShot: public WCondition
{
friend class WConditionOneShot_test;
public:
/**
* Default constructor.
*/
WConditionOneShot();
/**
* Destructor.
*/
virtual ~WConditionOneShot();
/**
* Wait for the condition. Sets the calling thread asleep.
*/
virtual void wait();
/**
* Notifies all waiting threads.
*/
virtual void notify();
protected:
/**
* Locked as long the condition was not fired.
*/
boost::unique_lock<boost::shared_mutex> m_lock;
private:
};
#endif // WCONDITIONONESHOT_H
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WCONDITION_TEST_H
#define WCONDITION_TEST_H
#include <iostream>
#include <boost/thread.hpp>
#include <cxxtest/TestSuite.h>
#include "../WConditionOneShot.h"
/**
* Helper class.
*/
class Callable
{
public:
bool flag;
WConditionOneShot* c;
void threadMain()
{
flag = true;
boost::this_thread::sleep( boost::posix_time::seconds( 1 ) );
c->notify();
};
};
/**
* Test WConditionOneShot
*/
class WConditionOneShotTest : public CxxTest::TestSuite
{
public:
/**
* An instantiation should never throw an exception, as well as tear down.
*/
void testInstantiation( void )
{
WConditionOneShot* c;
TS_ASSERT_THROWS_NOTHING( c = new WConditionOneShot() );
TS_ASSERT_THROWS_NOTHING( delete c );
}
/**
* Test whether notification is working.
*/
void testWaitNotify()
{
WConditionOneShot c;
Callable t;
t.flag = false;
t.c = &c;
// start a thread
boost::thread thread = boost::thread( boost::bind( &Callable::threadMain, &t ) );
// wait for condition
c.wait();
// since it is a one shot condition -> another wait will not cause a freeze
c.wait();
TS_ASSERT( t.flag );
}
};
#endif // WCONDITION_TEST_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment