📄 thread.h
字号:
/*************************************************************************** * * * 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. * * * ***************************************************************************//** * Copyright (c) 1999 * * A C++ implementation of posix threads, using Linux clone system * calls. * * This implementation provides threads, similar to the linuxthreads * package, except where each thread is a class here. * * @author Orn Hansen <oe.hansen@gamma.telenordia.se> * @short a C++ implementation of threads for linux. */#ifndef __THREADS_LIBRARY_H#define __THREADS_LIBRARY_H/** * This definition makes all classes loaded after it, to be thread * safe. Mainly, this is for the standard template library, which * will include some mutexes to ensure safety in allocation * classes. * * Make sure to load this file first, in your program. */#define _THREAD_SAFE#define DEFAULTMUTEX mutex_t()namespace cpp_threads {class Mutex;class Cond;class spinlock;};//// These definitions are required by the standard template library,// and we use a spinlock variable, to avoid inner conflict.//typedef cpp_threads::spinlock mutex_t;#define mutex_lock(x) ((mutex_t *)x)->acquire()#define mutex_unlock(x) ((mutex_t *)x)->release()#include <threads/stl.h>#include <threads/mutex.h>#include <threads/cond.h>#include <threads/semaphore.h>extern "C" {# include <setjmp.h># include <unistd.h>};#define CPPTHREAD_CANCELED (-1)#define CPPTHREAD_SIG_RESTART s_continue#define CPPTHREAD_SIG_CANCEL s_quitnamespace cpp_threads { class ThreadStack; /** * Threads, are cloned processes that share the same * memory for reading and writing. This is a primitive * and needs to be a superclass to any specific needs for * threaded execution. * * @short Abstract class for threads. * @author Orn Hansen <oe.hansen@gamma.telenordia.se> */ class Pthread { public: enum cancel_state { cancel_enable_e, cancel_disable_e }; enum cancel_type { cancel_deferred_e, cancel_asynchronous_e }; enum jumps { signal_jmp_e, cancel_jmp_e }; enum thread_state { p_running_e, p_stopped_e, p_suspended_e, p_canceled_e, p_terminated_e, p_exited_e, p_jointhread_e }; enum booleans { set_terminated_e, set_detached_e, set_exited_e, set_canceled_e, set_private_e }; private: Semaphore* _runner; pid_t _tid; pid_t _ppid; ThreadStack* _sp; spinlock _spinlock; attributes _attributes; int _priority; int _signal; int _joining; int _errno; void* _retval; int _retcode; sigjmp_buf* _signal_jmp; sigjmp_buf* _cancel_jmp; sigjmp_buf* _polled_jmp; thread_state _state; cancel_state _cancelstate; cancel_type _canceltype; void varinit(); void invoke(void *,Semaphore *,size_t); static int __routine(void *); protected: /** * These are routines that handle signals within the * threads. * * Initialize all signal handlers, on a thread start * ensuring terminating signals will get cought and * terminate the program properly. */ static void signal_init(); /** Suspend the thread, from an outside thread */ static void sig_stop(int); /** Cancel the thread */ static void sig_cancel(int); /** Generic handler */ static void sig_handler(int); /** Child exit, to remove children from zombie status. */ static void sig_childexit(int); /** Terminate the process, ensure program termination proper */ static void sig_terminate(int); protected: bool error(int val) { _errno = val; return false; }; /** * Cleanup() * * This will browse the list of threads, for any possible child * threads, and terminate these if possible. */ static void cleanup(); /** * exit_child() * * Does what is needed, when a child exits. */ static void exit_child(int); public: /** * Create a thread, without any starting arguments. * * When a thread is created, some compilers will not have * the virtual tables filled in at that time. It is also * to notice, that without control, the thread will start * before the constructor has finished creating the environment * the thread is to run in. By providing a semaphore as a * parameter, the thread will actually wait for a post on it * before activating the class thread. Giving the compiler * and user functions time to initalize before the thread * starts using variables in the class. * * <pre> * example: * * Semaphore sem; * Pthread *p = new mythread(&sem); * sem.post(); // or p->run(); * </pre> * * As of version 3.0, the above functionality is provided * by default. So, in version 3.0 and above, to actually * make the thread start, the following must be done... * * <pre> * example: * * Pthread *p = new mythread(); * p->run(); * </pre> * * @param sem A semaphore to control the thread initialisation. * @param pages Number of stack pages to allocate for the thread. */ Pthread(Semaphore* sem=0,size_t pages=0); /** * Create a thread, with starting arguements. This is equivalent * to the above routine, except for the arguement that is * provided. * * @param arg The arguement to send to the thread. * @param sem A semaphore to control the thread initialisation. * @param pages Number of stack pages to allocate for the thread. */ Pthread(void *,Semaphore* sem=0,size_t pages=0); /** * This is a convenience function, to create a controlling * environment around an existing routine. * * @param id The process id, of a running process. */ Pthread(int); virtual ~Pthread(); thread_state state(); thread_state state(thread_state); /** * An abstract definition of the method, that will be run * as a different process by this class. This is the starting * point, of the new process. * * In creating a new process, it should be taken care off that * the process itself, is starting its execution at the same * time as the construction is initializing class variables. This * may be unwanted, and to have a process wait for the initialization * to finish, the following method can be used. And is provided * by default, by an internal semaphore. * * <pre> * * #include <thread.h> * * class mythread : public Pthread { * private: * Semaphore run_away; * string something; * * public: * mythread() * { * something = "This has been initialized"; * run_away.post(); // last instruction in constructor. * } * ~mythread() * { * // TODO: destroy variables. * } * * int thread(void *) * { * run_away.wait(); * // Now, the process is synchronized to run after * // the initialisation has finished. * } * }; * * </pre> * * The above mechanism, can both be seen as a quirk, and as a drawback. * In most cases, the thread doesn't need the variables in its class, * so forcing the thread to wait until the constructor has finished * isn't necessary... and perhaps even unwanted. * * @param any The process will receive a parameter, whose type is only known internally. * @return Actually, nothing is returned here. See @ref #retval how to acquire return values. */ virtual int thread(void *) = 0; /** * If the class is initialized with a hold off semaphore, to allow * the constructor to conclude its job, then post to the semaphore * here, to cause the thread to run. */ void run(); /** * This method allows access to the value returned by the process, if * it has returned, that is. Otherwise, it contains an undefined value. * * @return A pointer, that the thread can register as a return value. */ void *retval() const { return _retval; }; /** * This method defines, wether the thread is joining with another * thread. The return value, is either the process id of the * thread that is to be joined with, or 0 which indicates that * it is not being joined with anyone. * * @return the pid of the process to join with. */ int joining() const { return _joining; }; /** * If an error has occurred, during the process, it will be locally * stored and can be retrieved by this method. Note however, that * it is upon the user to make sure that his thread sets this value * with the @ref #error function. * * @return The last errorvalue registered. */ int gerrno() const { return _errno; }; /** * Each thread has its own process id, and even though it is * possible with the clone system to clone the process id as well, * it is not done within this thread package. * * @return the pid of this thread. */ int id() const { return _tid; }; /** * Each thread has a parent process, and this is the stored * number of it. It is to simplify the manner in which * programs can achieve it, as they don't have to call * expansive kernel routines. */ int ppid() const { return _ppid; }; /** * Each time a thread receives a signal, it stores the * signal number locally so that parent threads can view * or debug its status. * * @return Last signal received by the thread. */ int signal() const { return _signal; }; /** * This is a convenience function, provided to simplify the * use of sending signals to a thread. If the user has access to * the thread class, he can use this method to signal the thread * instead of the system kill function. * * @return Last signal received by the thread. */ int signal(int); /** * A running thread can terminate in several ways, it can * terminate by returning or exiting from the thread, or it * can be canceled from inside or from an outside source. * This function reports if the thread was canceled. * * @return True if the thread has been canceled. */ bool canceled() const; /** * Usually all threads created by the main program will be * hanging on to it. This means, that when the main program * stops execution, the thread belonging to it will be * terminated when it exits. The thread can however detach * itself from the main thread. * * @return True if the thread has been detached. */ bool detached() const; /** * A detached thread, isn't joinable... there may also be * other situations where a thread does not want a parent * thread to join onto it. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -