#ifndef THREAD_H #define THREAD_H //$Id: Thread.h,v 1.20 2006/06/03 21:32:38 markus Rel $ // 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #ifdef HAVE_LIBPTHREAD # include #else # if !defined (HAVE_BEGINTHREAD) && defined (HAVE__BEGINTHREAD) # define HAVE_BEGINTHREAD # define beginthread _beginthread # define endthread _endthread # endif # if HAVE_WINDOWS_H # define WIN32_LEAN_AND_MEAN # include typedef void* (WINTHREAD_FUNCTION) (void*); # elif !defined (HAVE_BEGINTHREAD) # include # include # endif #endif #include namespace YGP { /**Class to execute a certain function in a thread There are two create-functions: The first calles the passed function with the parameters directly; the second passed a pointer to the created thread and enables to get the paramters with its getArgs-method. This enables controlling the thread. */ class Thread { public: /// Declaration of prototype of callback. typedef void* (*THREAD_FUNCTION) (void*); virtual ~Thread (); /// Creates a new thread; the argument is passed directly to the thread function /// \param fnc: Thread function to execute /// \param pArgs: Argument to the thread static Thread* create (THREAD_FUNCTION fnc, void* pArgs) throw (YGP::ExecError) { return new Thread (fnc, pArgs); } /// Creates a new thread; a pointer to the thread ID is passed to the thread function /// \param fnc: Thread function to execute /// \param pArgs: Argument to the thread static Thread* create2 (THREAD_FUNCTION fnc, void* pArgs) throw (YGP::ExecError) { Thread* t = new Thread; t->pArgs_ = pArgs; t->init (fnc, t); return t; } /// Returns the argument passed to the thread void* getArgs () const { return pArgs_; } /// \name Termination of the thread //@{ void allowCancelation (bool allow = true); void cancel (); static void* waitForThread (const Thread& id); static void* waitForThread (unsigned long threadID); void isToCancel () const; //@} /// Get the ID of the thread unsigned long getID () const { return (unsigned long)id; } /// Get the ID of the currently running thread static unsigned long currentID () { #ifdef HAVE_LIBPTHREAD return (unsigned long)pthread_self (); #elif defined HAVE_BEGINTHREAD # ifdef HAVE_WINDOWS_H return (unsigned long)GetCurrentThreadId (); # else # warning Method Thread::currentID () does not work! return (unsigned long)-1; # endif #else return (unsigned long)getpid (); #endif } protected: Thread (); Thread (THREAD_FUNCTION fnc, void* pArgs) throw (YGP::ExecError); void ret (void* rc) const; void init (THREAD_FUNCTION fnc, void* pArgs) throw (YGP::ExecError); void* pArgs_; ///< Pointer to (array of) arguments to the thread private: #ifdef HAVE_LIBPTHREAD pthread_t id; #else bool canceled; # if defined (HAVE_BEGINTHREAD) THREAD_FUNCTION callback; static void threadFunction (void* thread); unsigned long id; # else pid_t id; # endif #endif }; /**Class to execute a member-function in a thread. There are two create-functions: The first calles the passed function with the parameters directly; the second passed a pointer to the created thread and enables to get the paramters with its getArgs-method. This enables controlling the thread. */ template class OThread : public Thread { public: /// Declaration of type of callback typedef void* (T::*THREAD_OBJMEMBER) (void*); /// Destructor ~OThread () { } /// Creates a new thread; the argument is passed directly to the thread function /// \param obj: Object having a member to execute in a thread /// \param fnc: Member to execute as thread /// \param pArgs: Argument to the thread static OThread* create (T* obj, THREAD_OBJMEMBER fnc, void* pArgs) throw (YGP::ExecError) { return new OThread (obj, fnc, pArgs); } /// Creates a new thread; a pointer to the thread is passed to the thread function /// \param obj: Object having a member to execute in a thread /// \param fnc: Member to execute as thread /// \param pArgs: Argument to the thread static OThread* create2 (T* obj, THREAD_OBJMEMBER fnc, void* pArgs) throw (YGP::ExecError) { return new OThread (obj, fnc, pArgs, true); } protected: /// Constructor /// \param obj: Object having a member to execute in a thread /// \param fnc: Member to execute as thread /// \param pArgs: Argument to the thread /// \param threadAsArg: Flag, if the thread expects its argument directly OThread (T* obj, THREAD_OBJMEMBER fnc, void* pArgs, bool threadAsArg = false) throw (YGP::ExecError) : Thread (), indirect (threadAsArg), object (obj), callback (fnc) { // Don't create Thread directly with data, because the thread might start // without object and callback being initialized!! pArgs_ = pArgs; init (&proxy, this); } private: static void* proxy (void* pArgs) { OThread* thread = static_cast *> (pArgs); void* rc = ((thread->object)->*(thread->callback)) (thread->indirect ? thread : thread->getArgs ()); delete thread; return rc; } bool indirect; T* object; THREAD_OBJMEMBER callback; }; } #endif