|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (C) 2001 Stefan Westerfeld
|
|
|
|
stefan@space.twc.de
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library 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
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef ARTS_MCOP_THREAD_H
|
|
|
|
#define ARTS_MCOP_THREAD_H
|
|
|
|
|
|
|
|
#include "arts_export.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* BC - Status (2002-03-08): SystemThreads, Thread, Mutex, ThreadCondition,
|
|
|
|
* Semaphore
|
|
|
|
*
|
|
|
|
* These classes are kept binary compatible. As the threading implementation
|
|
|
|
* can be changed, also
|
|
|
|
*
|
|
|
|
* Thread_impl, Mutex_impl, ThreadCondition_impl and Semaphore_impl need
|
|
|
|
* to remain as they are. The implementation of these depends on what thread
|
|
|
|
* system is used, and can attach the required data as necessary to the
|
|
|
|
* base classes. So i.e. a posix mutex can contain the pthread_mutex_t in
|
|
|
|
* the PosixMutex_impl.
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace Arts {
|
|
|
|
|
|
|
|
class Mutex_impl;
|
|
|
|
class Thread_impl;
|
|
|
|
class ThreadCondition_impl;
|
|
|
|
class Thread;
|
|
|
|
class Semaphore_impl;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Encapsulates the operating system threading facilities
|
|
|
|
*/
|
|
|
|
class ARTS_EXPORT SystemThreads {
|
|
|
|
public:
|
|
|
|
static SystemThreads *the();
|
|
|
|
static bool init(SystemThreads *the);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check whether there is threading support available
|
|
|
|
*
|
|
|
|
* If there is no real threading support, the Threading classes try to
|
|
|
|
* gracefully degrade the performance. For instance, locking a mutex will
|
|
|
|
* do * nothing, and calling the start() function of a Thread will execute
|
|
|
|
* it's run function.
|
|
|
|
*
|
|
|
|
* @returns true if there are real threads
|
|
|
|
*/
|
|
|
|
static bool supported();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check wether the current thread is the main thread
|
|
|
|
*
|
|
|
|
* The main thread is the thread that the application's main() was
|
|
|
|
* executed in. The IOManager event loop will only run in the main
|
|
|
|
* thread.
|
|
|
|
*/
|
|
|
|
virtual bool isMainThread() = 0;
|
|
|
|
|
|
|
|
virtual Mutex_impl *createMutex_impl() = 0;
|
|
|
|
virtual Mutex_impl *createRecMutex_impl() = 0;
|
|
|
|
virtual Thread_impl *createThread_impl(Thread *thread) = 0;
|
|
|
|
virtual ThreadCondition_impl *createThreadCondition_impl() = 0;
|
|
|
|
virtual Semaphore_impl *createSemaphore_impl(int, int) = 0;
|
|
|
|
virtual ~SystemThreads();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a pointer to the current thread, or a null pointer if
|
|
|
|
* we're the main thread (isMainThread() is true).
|
|
|
|
*/
|
|
|
|
virtual Thread *getCurrentThread() = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Base class for platform specific thread code
|
|
|
|
*/
|
|
|
|
class ARTS_EXPORT Thread_impl
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual void setPriority(int) =0;
|
|
|
|
virtual void start() = 0;
|
|
|
|
virtual void waitDone() = 0;
|
|
|
|
virtual ~Thread_impl();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Base class for platform specific mutex code
|
|
|
|
*/
|
|
|
|
class ARTS_EXPORT Mutex_impl {
|
|
|
|
public:
|
|
|
|
virtual void lock() = 0;
|
|
|
|
virtual bool tryLock() = 0;
|
|
|
|
virtual void unlock() = 0;
|
|
|
|
virtual ~Mutex_impl();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Base class for platform specific thread condition code
|
|
|
|
*/
|
|
|
|
class ARTS_EXPORT ThreadCondition_impl {
|
|
|
|
public:
|
|
|
|
virtual void wakeOne() = 0;
|
|
|
|
virtual void wakeAll() = 0;
|
|
|
|
virtual void wait(Mutex_impl *impl) = 0;
|
|
|
|
virtual ~ThreadCondition_impl();
|
|
|
|
};
|
|
|
|
|
|
|
|
class ARTS_EXPORT Semaphore_impl {
|
|
|
|
public:
|
|
|
|
virtual void wait() = 0;
|
|
|
|
virtual int tryWait() = 0;
|
|
|
|
virtual void post() = 0;
|
|
|
|
virtual int getValue() = 0;
|
|
|
|
virtual ~Semaphore_impl();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A thread of execution
|
|
|
|
*
|
|
|
|
* Example for implementing a thread:
|
|
|
|
*
|
|
|
|
* <pre>
|
|
|
|
* class Counter : public Arts::Thread
|
|
|
|
* {
|
|
|
|
* public:
|
|
|
|
* void run() {
|
|
|
|
* for(int i = 0;i < 10;i++)
|
|
|
|
* {
|
|
|
|
* printf("%d\n",i+1);
|
|
|
|
* sleep(1);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* }; // start the thread with Counter c; c.start();
|
|
|
|
* </pre>
|
|
|
|
*/
|
|
|
|
class ARTS_EXPORT Thread {
|
|
|
|
private:
|
|
|
|
Thread_impl *impl;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Thread() : impl(SystemThreads::the()->createThread_impl(this))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~Thread();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* set the priority parameters for the thread
|
|
|
|
*
|
|
|
|
* FIXME: what should be minimum, maximum, recommended?
|
|
|
|
*/
|
|
|
|
inline void setPriority(int priority) {
|
|
|
|
impl->setPriority(priority);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* starts the run() method in a thread
|
|
|
|
*/
|
|
|
|
inline void start()
|
|
|
|
{
|
|
|
|
impl->start();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* waits until the thread is executed completely
|
|
|
|
*/
|
|
|
|
inline void waitDone()
|
|
|
|
{
|
|
|
|
impl->waitDone();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* implement this method, if you want to create an own thread - then
|
|
|
|
* you can simply call thread.start() to start execution of run() in
|
|
|
|
* a seperate thread
|
|
|
|
*/
|
|
|
|
virtual void run() = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A mutex
|
|
|
|
*
|
|
|
|
* To protect a critical section, you can use a mutex, which will ensure that
|
|
|
|
* only one thread at a time can lock it. Here is an example for a thread-safe
|
|
|
|
* random number generator:
|
|
|
|
*
|
|
|
|
* <pre>
|
|
|
|
* class RandomGenerator {
|
|
|
|
* Arts::Mutex mutex;
|
|
|
|
* long seed;
|
|
|
|
* public:
|
|
|
|
* long get() {
|
|
|
|
* mutex.lock();
|
|
|
|
* // do complicated calculation with seed here
|
|
|
|
* mutex.unlock();
|
|
|
|
* return seed;
|
|
|
|
* }
|
|
|
|
* };
|
|
|
|
* </pre>
|
|
|
|
*/
|
|
|
|
class ARTS_EXPORT Mutex {
|
|
|
|
private:
|
|
|
|
Mutex_impl *impl;
|
|
|
|
friend class ThreadCondition;
|
|
|
|
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* constructor
|
|
|
|
*
|
|
|
|
* @param recursive whether to create a recursive mutex (may be locked by
|
|
|
|
* the same thread more than once), or a normal mutex
|
|
|
|
*/
|
|
|
|
inline Mutex(bool recursive = false)
|
|
|
|
: impl(recursive?SystemThreads::the()->createRecMutex_impl()
|
|
|
|
:SystemThreads::the()->createMutex_impl())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* destructor
|
|
|
|
*/
|
|
|
|
virtual ~Mutex();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* locks the mutex
|
|
|
|
*/
|
|
|
|
inline void lock() {
|
|
|
|
impl->lock();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* tries to lock the mutex, returning immediately in any case (even if
|
|
|
|
* mutex is locked by another thread)
|
|
|
|
*
|
|
|
|
* @returns true if successful (mutex locked), false otherwise
|
|
|
|
*/
|
|
|
|
inline bool tryLock() {
|
|
|
|
return impl->tryLock();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* unlocks the mutex
|
|
|
|
*/
|
|
|
|
inline void unlock() {
|
|
|
|
impl->unlock();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A thread condition
|
|
|
|
*
|
|
|
|
* Thread conditions are used to let a different thread know that a certain
|
|
|
|
* condition might have changed. For instance, if you have a thread that
|
|
|
|
* waits until a counter exceeds a limit, the thread would look like this:
|
|
|
|
*
|
|
|
|
* <pre>
|
|
|
|
* class WaitCounter : public Arts::Thread
|
|
|
|
* {
|
|
|
|
* int counter;
|
|
|
|
* Arts::Mutex mutex;
|
|
|
|
* Arts::ThreadCondition cond;
|
|
|
|
*
|
|
|
|
* public:
|
|
|
|
* WaitCounter() : counter(0) {}
|
|
|
|
*
|
|
|
|
* void run() { // run will terminate once the counter reaches 20
|
|
|
|
* mutex.lock();
|
|
|
|
* while(counter < 20)
|
|
|
|
* cond.wait(mutex);
|
|
|
|
* mutex.unlock();
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* void inc() { // inc will increment the counter and indicate the change
|
|
|
|
* mutex.lock();
|
|
|
|
* counter++;
|
|
|
|
* cond.wakeOne();
|
|
|
|
* mutex.unlock();
|
|
|
|
* }
|
|
|
|
* };
|
|
|
|
* </pre>
|
|
|
|
*/
|
|
|
|
class ARTS_EXPORT ThreadCondition {
|
|
|
|
private:
|
|
|
|
ThreadCondition_impl *impl;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ThreadCondition()
|
|
|
|
: impl(SystemThreads::the()->createThreadCondition_impl())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~ThreadCondition();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* wakes one waiting thread
|
|
|
|
*/
|
|
|
|
inline void wakeOne()
|
|
|
|
{
|
|
|
|
impl->wakeOne();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* wakes all waiting threads
|
|
|
|
*/
|
|
|
|
inline void wakeAll()
|
|
|
|
{
|
|
|
|
impl->wakeAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Waits until the condition changes. You will need to lock the mutex
|
|
|
|
* before calling this. Internally it will unlock the mutex (to let
|
|
|
|
* others change the condition), and relock it once the wait succeeds.
|
|
|
|
*/
|
|
|
|
inline void wait(Mutex& mutex)
|
|
|
|
{
|
|
|
|
impl->wait(mutex.impl);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class ARTS_EXPORT Semaphore {
|
|
|
|
private:
|
|
|
|
Semaphore_impl *impl;
|
|
|
|
|
|
|
|
public:
|
|
|
|
Semaphore(int shared=0, int count=0)
|
|
|
|
{
|
|
|
|
impl = SystemThreads::the()->createSemaphore_impl(shared, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual ~Semaphore();
|
|
|
|
|
|
|
|
inline void wait()
|
|
|
|
{
|
|
|
|
impl->wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int tryWait()
|
|
|
|
{
|
|
|
|
return impl->tryWait();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void post()
|
|
|
|
{
|
|
|
|
impl->post();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int getValue()
|
|
|
|
{
|
|
|
|
return impl->getValue();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* ARTS_MCOP_THREAD_H */
|