Files
simgear/simgear/threads/SGThread.hxx
ehofman 733e6fa14f Reduce compiler.h to almost nothing (but it's worth keeping around I think, for
the MSVC and MipsPro warning stuff).

As a result of this patch, simgear/sg_traits.h can be deleted. So can SGCMath.h,
but I'll do that separately.

There is one more 'mechanical' change to come - getting rid of SG_USING_STD(X),
but I want to keep that separate from everything else. (There's another mechnica
l change, replacing <math.h> with <cmath> and so on *everywhere*, but one step a
t a time)
2008-07-25 18:35:40 +00:00

344 lines
7.7 KiB
C++

// SGThread - Simple pthread class wrappers.
//
// Written by Bernie Bright, started April 2001.
//
// Copyright (C) 2001 Bernard Bright - bbright@bigpond.net.au
//
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef SGTHREAD_HXX_INCLUDED
#define SGTHREAD_HXX_INCLUDED 1
#include <simgear/compiler.h>
#include <pthread.h>
#include <cassert>
#include <cerrno>
class SGThread;
extern "C" {
void* start_handler( void* );
};
/**
* Encapsulate generic threading methods.
* Users derive a class from SGThread and implement the run() member function.
*/
class SGThread
{
public:
/**
* SGThread cancelation modes.
*/
enum cancel_t
{
CANCEL_DISABLE = 0,
CANCEL_DEFERRED,
CANCEL_IMMEDIATE
};
public:
/**
* Create a new thread object.
* When a SGThread object is created it does not begin execution
* immediately. It is started by calling the start() member function.
*/
SGThread();
/**
* Start the underlying thread of execution.
* @param cpu An optional parameter to specify on which CPU to run this
* thread (only supported on IRIX at this time).
* @return Pthread error code if execution fails, otherwise returns 0.
*/
int start( unsigned cpu = 0 );
/**
* Sends a cancellation request to the underlying thread. The target
* thread will either ignore the request, honor it immediately or defer
* it until it reaches a cancellation point.
*/
void cancel();
/**
* Suspends the exection of the calling thread until this thread
* terminates.
*/
void join();
protected:
/**
* Destroy a thread object.
* This is protected so that its illegal to simply delete a thread
* - it must return from its run() function.
*/
virtual ~SGThread();
/**
* Set the threads cancellation mode.
* @param mode The required cancellation mode.
*/
void set_cancel( cancel_t mode );
/**
* All threads execute by deriving the run() method of SGThread.
* If this function terminates then the thread also terminates.
*/
virtual void run() = 0;
private:
/**
* Pthread thread identifier.
*/
pthread_t tid;
friend void* start_handler( void* );
private:
// Disable copying.
SGThread( const SGThread& );
SGThread& operator=( const SGThread& );
};
inline
SGThread::SGThread()
{
}
inline
SGThread::~SGThread()
{
}
inline int
SGThread::start( unsigned cpu )
{
int status = pthread_create( &tid, 0, start_handler, this );
assert( status == 0 );
(void)status;
#if defined( sgi )
if ( !status && !cpu )
pthread_setrunon_np( cpu );
#endif
return status;
}
inline void
SGThread::join()
{
int status = pthread_join( tid, 0 );
assert( status == 0 );
(void)status;
}
inline void
SGThread::cancel()
{
int status = pthread_cancel( tid );
assert( status == 0 );
(void)status;
}
/**
* A mutex is used to protect a section of code such that at any time
* only a single thread can execute the code.
*/
class SGMutex
{
friend class SGPthreadCond;
public:
/**
* Create a new mutex.
* Under Linux this is a 'fast' mutex.
*/
SGMutex();
/**
* Destroy a mutex object.
* Note: it is the responsibility of the caller to ensure the mutex is
* unlocked before destruction occurs.
*/
~SGMutex();
/**
* Lock this mutex.
* If the mutex is currently unlocked, it becomes locked and owned by
* the calling thread. If the mutex is already locked by another thread,
* the calling thread is suspended until the mutex is unlocked. If the
* mutex is already locked and owned by the calling thread, the calling
* thread is suspended until the mutex is unlocked, effectively causing
* the calling thread to deadlock.
*
* @see SGMutex::trylock
*/
void lock();
/**
* Try to lock the mutex for the current thread. Behaves like lock except
* that it doesn't block the calling thread.
* @return true if mutex was successfully locked, otherwise false.
* @see SGMutex::lock
*/
bool trylock();
/**
* Unlock this mutex.
* It is assumed that the mutex is locked and owned by the calling thread.
*/
void unlock();
protected:
/**
* Pthread mutex.
*/
pthread_mutex_t mutex;
};
inline SGMutex::SGMutex()
{
int status = pthread_mutex_init( &mutex, 0 );
assert( status == 0 );
(void)status;
}
inline SGMutex::~SGMutex()
{
int status = pthread_mutex_destroy( &mutex );
assert( status == 0 );
(void)status;
}
inline void SGMutex::lock()
{
int status = pthread_mutex_lock( &mutex );
assert( status == 0 );
(void)status;
}
inline void SGMutex::unlock()
{
int status = pthread_mutex_unlock( &mutex );
assert( status == 0 );
(void)status;
}
/**
* A condition variable is a synchronization device that allows threads to
* suspend execution until some predicate on shared data is satisfied.
* A condition variable is always associated with a mutex to avoid race
* conditions.
*/
class SGPthreadCond
{
public:
/**
* Create a new condition variable.
*/
SGPthreadCond();
/**
* Destroy the condition object.
*/
~SGPthreadCond();
/**
* Wait for this condition variable to be signaled.
*
* @param SGMutex& reference to a locked mutex.
*/
void wait( SGMutex& );
/**
* Wait for this condition variable to be signaled for at most
* 'ms' milliseconds.
*
* @param mutex reference to a locked mutex.
* @param ms milliseconds to wait for a signal.
*
* @return
*/
bool wait( SGMutex& mutex, unsigned long ms );
/**
* Wake one thread waiting on this condition variable.
* Nothing happens if no threads are waiting.
* If several threads are waiting exactly one thread is restarted. It
* is not specified which.
*/
void signal();
/**
* Wake all threads waiting on this condition variable.
* Nothing happens if no threads are waiting.
*/
void broadcast();
private:
// Disable copying.
SGPthreadCond(const SGPthreadCond& );
SGPthreadCond& operator=(const SGPthreadCond& );
private:
/**
* The Pthread conditon variable.
*/
pthread_cond_t cond;
};
inline SGPthreadCond::SGPthreadCond()
{
int status = pthread_cond_init( &cond, 0 );
assert( status == 0 );
(void)status;
}
inline SGPthreadCond::~SGPthreadCond()
{
int status = pthread_cond_destroy( &cond );
assert( status == 0 );
(void)status;
}
inline void SGPthreadCond::signal()
{
int status = pthread_cond_signal( &cond );
assert( status == 0 );
(void)status;
}
inline void SGPthreadCond::broadcast()
{
int status = pthread_cond_broadcast( &cond );
assert( status == 0 );
(void)status;
}
inline void SGPthreadCond::wait( SGMutex& mutex )
{
int status = pthread_cond_wait( &cond, &mutex.mutex );
assert( status == 0 );
(void)status;
}
#endif /* SGTHREAD_HXX_INCLUDED */