iAdded new classes to simgear/threads. SGGuard is a wrapper around a

mutex that unlocks the mutex when the SGGuard object goes out of scope.
The SGxxxQueue<T> template family factor out the common behaviour we
need for passing data between threads.
This commit is contained in:
curt
2001-04-16 17:26:13 +00:00
parent 187258cc3a
commit 4f3aaa1ede
4 changed files with 250 additions and 2 deletions

View File

@@ -345,7 +345,7 @@ if test "x$ac_cv_header_zlib_h" != "xyes"; then
fi
if test "x$ac_cv_lib_pthread_pthread_exit" = "xyes" -a "x$ac_cv_header_pthread_h" = "xyes"; then
echo "Threads: pthread is supported."
echo "Threads: pthread lib found."
else
echo "Threads: no threads (pthreads not found.)"
echo "Threads: no threads (pthread lib not found.)"
fi

View File

@@ -3,6 +3,8 @@ includedir = @includedir@/threads
lib_LIBRARIES = libsgthreads.a
include_HEADERS = \
SGGuard.hxx \
SGQueue.hxx \
SGThread.hxx
libsgthreads_a_SOURCES = \

View File

@@ -0,0 +1,38 @@
#ifndef SGGUARD_HXX_INCLUDED
#define SGGUARD_HXX_INCLUDED 1
/**
* A scoped locking utility.
* An SGGuard object locks its synchronization object during creation and
* automatically unlocks it when it goes out of scope.
*/
template<class LOCK>
class SGGuard
{
public:
/**
* Create an SGGuard object and lock the passed lockable object.
* @param LOCK A lockable object.
*/
inline SGGuard( LOCK& l ) : lock(l) { lock.lock(); }
/**
* Destroy this object and unlock the locakable object.
*/
inline ~SGGuard() { lock.unlock(); }
private:
/**
* A lockable object.
*/
LOCK& lock;
private:
// Disable copying.
SGGuard(const LOCK&);
LOCK& operator= (const LOCK&);
};
#endif // SGGUARD_HXX_INCLUDED

208
simgear/threads/SGQueue.hxx Normal file
View File

@@ -0,0 +1,208 @@
#ifndef SGQUEUE_HXX_INCLUDED
#define SGQUEUE_HXX_INCLUDED 1
#include <simgear/compiler.h>
#if defined ( SG_HAVE_STD_INCLUDES )
# include <cassert>
#else
# include <assert.h>
#endif
#include <queue>
#include "SGThread.hxx"
#include "SGGuard.hxx"
/**
* SGQueue defines an interface for a FIFO.
* It can be implemented using different types of synchronization
* and protection.
*/
template<class T>
class SGQueue
{
public:
/**
* Create a new SGQueue object.
*/
SGQueue() {}
/**
* Destroy this object.
*/
virtual ~SGQueue() {}
/**
* Returns whether this queue is empty (contains no elements).
*
* @return bool True if queue is empty, otherwisr false.
*/
virtual bool empty() = 0;
/**
* Add an item to the end of the queue.
*
* @param T object to add.
*/
virtual void push( const T& item ) = 0;
/**
* Get an item from the head of the queue.
*
* @return T next available object.
*/
virtual T pop() = 0;
protected:
/**
*
*/
std::queue<T> fifo;
};
/**
* A simple thread safe queue. All access functions are guarded with a mutex.
*/
template<class T, class LOCK=SGMutex>
class SGLockedQueue : public SGQueue<T>
{
public:
/**
* Create a new SGLockedQueue object.
*/
SGLockedQueue() {}
/**
* Destroy this object.
*/
~SGLockedQueue() {}
/**
* Returns whether this queue is empty (contains no elements).
*
* @return bool True if queue is empty, otherwisr false.
*/
virtual bool empty() {
SGGuard<LOCK> g(mutex);
return fifo.empty();
}
/**
* Add an item to the end of the queue.
*
* @param T object to add.
*/
virtual void push( const T& item ) {
SGGuard<LOCK> g(mutex);
fifo.push( item );
}
/**
* Get an item from the head of the queue.
*
* @return T next available object.
*/
virtual T pop() {
SGGuard<LOCK> g(mutex);
//if (fifo.empty()) throw NoSuchElementException();
assert( ! fifo.empty() );
// if (fifo.empty())
// {
// mutex.unlock();
// pthread_exit( PTHREAD_CANCELED );
// }
T item = fifo.front();
fifo.pop();
return item;
}
private:
/**
* Mutex to serialise access.
*/
LOCK mutex;
private:
// Prevent copying.
SGLockedQueue(const SGLockedQueue&);
SGLockedQueue& operator= (const SGLockedQueue&);
};
/**
* A guarded queue blocks threads trying to retrieve items
* when none are available.
*/
template<class T>
class SGBlockingQueue : public SGQueue<T>
{
public:
/**
* Create a new SGBlockingQueue.
*/
SGBlockingQueue() {}
/**
* Destroy this queue.
*/
~SGBlockingQueue() { mutex.unlock(); }
/**
*
*/
virtual bool empty() {
SGGuard<SGMutex> g(mutex);
return fifo.empty();
}
/**
* Add an item to the end of the queue.
*
* @param T object to add.
*/
virtual void push( const T& item ) {
SGGuard<SGMutex> g(mutex);
fifo.push( item );
not_empty.signal();
}
/**
* Get an item from the head of the queue.
* If no items are available then the calling thread is suspended
*
* @return T next available object.
*/
virtual T pop() {
SGGuard<SGMutex> g(mutex);
while (fifo.empty())
not_empty.wait(mutex);
assert(fifo.empty() != true);
//if (fifo.empty()) throw ??
T item = fifo.front();
fifo.pop();
return item;
}
private:
/**
* Mutex to serialise access.
*/
SGMutex mutex;
/**
* Condition to signal when queue not empty.
*/
SGCondition not_empty;
private:
// Prevent copying.
SGBlockingQueue( const SGBlockingQueue& );
SGBlockingQueue& operator=( const SGBlockingQueue& );
};
#endif // SGQUEUE_HXX_INCLUDED