📄 pthreads.h
字号:
if (sem_trywait(&_s) < 0) { switch (errno) { case EPERM: ret = MICOMT::Semaphore::NoPermission; break; case EAGAIN: ret = MICOMT::Semaphore::TryAgain; break; case EINVAL: ret = MICOMT::Semaphore::SemInvalid; break; case EINTR: ret = MICOMT::Semaphore::Interrupted; break; default: ret = MICOMT::Semaphore::UnknownError; } } return ret; } /*! * The post method increases the count of the semaphore. */ void post() {#ifdef MTDEBUG if (MICO::Logger::IsLogged (MICO::Logger::Thread)) { __mtdebug_lock(); MICO::Logger::Stream (MICO::Logger::Thread) __NAME(<< name ()) << ": Semaphore::post ()" << endl; __mtdebug_unlock(); }#endif // MTDEBUG sem_post(&_s); } //@}};#else // HAVE_SEMAPHORE_H && !(__APPLE__ && __MACH__)// the OS doesn't provide POSIX semaphore implementation// in semaphore.h header file so we will use own// implementation based on mutex and condition variable//// This code is w/o doxygen doc because Doxyfile defines// HAVE_SEMAPHORE_H and so this code is not used for generating// documentation//class Semaphore#ifdef DEBUG_NAMES : public NamedObject#endif{ Mutex _mutex; CondVar _condition; unsigned int _counter;public: enum ErrorType { NoError, NoPermission, TryAgain, SemInvalid, Interrupted, UnknownError }; Semaphore(unsigned int value = 0) : _condition(&_mutex), _counter(value) {} ~Semaphore() {} void wait(); Semaphore::ErrorType trylock(); void post();};#endif // HAVE_SEMAPHORE_H && !(__APPLE__ && __MACH__)//// Thread///*! * \ingroup micomt * * The thread class is a thread abstraction for system thread types. * Each thread object encapsulates a single execution context. */class Thread#ifdef DEBUG_NAMES : public NamedObject#endif{public: /*! * \enum DetachFlag * * A thread may either be created Detached or NotDetached (attached) * to its parent thread. The DetachFlag is used to determine the * threads behavior when it exits. */ enum DetachFlag { Detached, //!< Detached threads are capable of //!< reclaiming their resources on exit. NotDetached //!< Attached threads must be re-joined with //!< the parent thread, allowing on-exit //!< synchronization. }; /*! * \enum ErrorType * * Error types associated with the Thread class. */ enum ErrorType { NoError, //!< No error on the thread ThreadFailure, //!< The thread has failed InvalidPriority, //!< The thread was given an invalid priority MutexAlreadyLocked, //!< Mutex is already locked NotStarted, //!< The thread has not started UnknownError //!< Unknown error. }; //! \name Constructor/Destructor //@{ Thread(DetachFlag detached = NotDetached); virtual ~Thread (); //@} /*! * \type ThreadId * * An opaque type for thread ids. */ typedef pthread_t ThreadID; /*! * \type ThreadKey * * An opaque type for thread key types. A thread key * is used to create and access thread specific data. */ typedef pthread_key_t ThreadKey; /* * \type ThreadNo * * An opaque type for internal thread numbering in * MICO. */ typedef MICO_ULong ThreadNo; //! \name Priority Methods //@{ /*! * This function is used to get the maximum priority for * the operating system. * * \return The maximum thread priority */ static int get_priority_max() { int policy; pthread_t id = pthread_self(); struct sched_param params; pthread_getschedparam(id, &policy, ¶ms); return sched_get_priority_max(policy); }; /*! * This function is used to get the minimum priority for * the operating system. * * \return The minimum thread priority */ static int get_priority_min() { int policy; pthread_t id = pthread_self(); struct sched_param params; pthread_getschedparam(id, &policy, ¶ms); return sched_get_priority_min(policy); }; /*! * The priority method is used to set new priority of the thread */ virtual void priority(MICO_Long new_priority); //@} //! \name Thread Specific Data Methods //@{ /*! * The create_key method creates a thread specific data key. This key can * be associated with an arbitrary data value using set_specific() * method. * * NOTE: It might be worthwhile to re-consider the designe of TSD * to just be a single class that maintains the association - sort * of a safe pointer class. It would at least be a fun programming * excercise. * * \param key The key to create * \param cleanup A cleanup method for the key */ static void create_key(ThreadKey& key, void (*__cleanup) (void *) = 0) { int result = pthread_key_create(&key, __cleanup); assert(result == 0); }; /*! * The delete_key method is used to delete a key, but not the data * associated with it. That is done on thread exit or cancellation. * * \param key The key to delete */ static void delete_key(ThreadKey& key) { int result = pthread_key_delete(key); assert(result == 0); }; /*! * The get_specific method is used to retrieve thread specific data * for a key. * * \param key The key for which to get data * \return A pointer to the thread specific data */ static void* get_specific(const ThreadKey& key) { return pthread_getspecific(key); }; /*! * The set_specific method is used to associate thread specific * data with a key. * * \param key The key to associate with data * \param value Thread specific data */ static void set_specific(const ThreadKey& key, void *value) { int result = pthread_setspecific(key, value); assert(result == 0); }; //@} //! \name Thread Identification Methods //@{ /*! * This method returns the threads system (pthread) id. * * \return The thread's system id */ ThreadID id() const { return _id; }; /*! * This method returns the threads system (pthread) id. This * method may be called without a thread object since it is * static. * * \return The thread's system id. */ static ThreadID self() { return pthread_self(); }; /*! * This method returns the thread number. * * \return The thread number (MICO specific) */ ThreadNo no() const { return _no; }; /*! * Sets the thread number to n (MICO specific). * * \param n The new thread number */ void no(const ThreadNo n) { _no = n; }; //@} //! \name Operators //@{ virtual MICO_Boolean operator==(const Thread &thread) const; //@} //! \name Thread Execution Methods //!@{ /*! * This method calls the run method. * * \param arg Thread parameters */ // create a new thread with _run a its start method // maybe we should throw a exception instead of returning an error code void _thr_startup(void *arg); /*! * This method is used to actually create the thread context and * start the thread initialization. * * \return A thread error condition */ ErrorType create_thread() {#ifdef MTDEBUG if (MICO::Logger::IsLogged (MICO::Logger::Thread)) { __mtdebug_lock(); MICO::Logger::Stream (MICO::Logger::Thread) << "Thread::create_thread ()" << endl; __mtdebug_unlock(); }#endif // MTDEBUG#ifdef _THR_CREATE_AND_BLOCK _ready.lock();#endif // _THR_CREATE_AND_BLOCK if (pthread_create(&_id, NULL, ThreadWrapper, this) != 0) {#ifdef MTDEBUG if (MICO::Logger::IsLogged (MICO::Logger::Thread)) { __mtdebug_lock(); MICO::Logger::Stream (MICO::Logger::Thread) << "Thread: pthread_create () returned: " << strerror (r) << endl; __mtdebug_unlock(); }#endif // MTDEBUG return ThreadFailure; } if (_detached == Detached) pthread_detach (_id); return NoError; }; /*! * Yield to another process or thread. This is considerate thing * to do for threads stuck in long loops. */ void yield() {#ifdef HAVE_SCHED_H sched_yield();#endif // HAVE_SCHED_H }; /*! * The start method will start thread a-la Java * * \return possible error while starting thread */ virtual ErrorType start(void* arg = NULL); /*! * The _run method is method which every thread executes. It's the * right place to do the work. The user can easily use Thread * class similar in Java i.e. inherit from Thread to custom class, * overload _run method and call start on class instance. * * Example: * \code * class MyThread : public virtual MICOMT::Thread * { * public: * void _run(void* arg = NULL) * { * // do the work here * } * }; * .... * MyThread* thr = new MyThread; * thr->start(); * thr->wait(); * \endcode */ virtual void _run(void* arg) = 0; static void* ThreadWrapper(void* arg); /*! * This method effectively cancels the thread from outside the * thread's context, effectively preventing cleanup. */ void terminate() {#ifdef MTDEBUG if (MICO::Logger::IsLogged (MICO::Logger::Thread)) { __mtdebug_lock(); MICO::Logger::Stream (MICO::Logger::Thread) __NAME(<< name ()) << ": Thread::terminate (void *exitval)" << endl; __mtdebug_unlock(); }#endif // MTDEBUG int result = pthread_cancel(this->id()); assert(!result); }; /*! * This method blocks the current thread until the thread being called * upon exits. * * \param exitval A place to store the exit value of the finished * thread */ void wait(void** exitval = NULL) {#ifdef MTDEBUG if (MICO::Logger::IsLogged (MICO::Logger::Thread)) { __mtdebug_lock(); MICO::Logger::Stream (MICO::Logger::Thread) __NAME(<< name ()) << ": Thread::wait()" << endl; __mtdebug_unlock(); }#endif // MTDEBUG pthread_join(this->id(), exitval); }; //@}protected: void* _arg; //!< Parameters passed in on start ThreadID _id; //!< The system thread id ThreadNo _no; //!< MICO thread number DetachFlag _detached; //!< Thread attached or detached?#ifdef _THR_CREATE_AND_BLOCK Mutex _ready; //!< Blocks thread on create (if specified) ErrorType _start_error; //!< Used to carry starting error from ctor to start method#endif // _THR_CREATE_AND_BLOCK};#endif // __OS_THREAD_PTHREADS_H__
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -