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)
344 lines
7.7 KiB
C++
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 */
|