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:
@@ -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
|
||||
|
||||
@@ -3,6 +3,8 @@ includedir = @includedir@/threads
|
||||
lib_LIBRARIES = libsgthreads.a
|
||||
|
||||
include_HEADERS = \
|
||||
SGGuard.hxx \
|
||||
SGQueue.hxx \
|
||||
SGThread.hxx
|
||||
|
||||
libsgthreads_a_SOURCES = \
|
||||
|
||||
38
simgear/threads/SGGuard.hxx
Normal file
38
simgear/threads/SGGuard.hxx
Normal 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
208
simgear/threads/SGQueue.hxx
Normal 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
|
||||
Reference in New Issue
Block a user