📄 thread.cpp
字号:
// Copyright (C) 1999-2005 Open Source Telecom Corporation.// // 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.// // As a special exception, you may use this file as part of a free software// library without restriction. Specifically, if other files instantiate// templates or use macros or inline functions from this file, or you compile// this file and link it with other files to produce an executable, this// file does not by itself cause the resulting executable to be covered by// the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by// the GNU General Public License. //// This exception applies only to the code released under the name GNU// Common C++. If you copy code from other releases into a copy of GNU// Common C++, as the General Public License permits, the exception does// not apply to the code that you add in this way. To avoid misleading// anyone as to the status of such modified files, you must delete// this exception notice from them.//// If you write modifications of your own for GNU Common C++, it is your choice// whether to permit this exception to apply to your modifications.// If you do not wish that, delete this exception notice.//#include <cc++/config.h>#include <cc++/export.h>#include <cc++/thread.h>#include <cc++/exception.h>#ifdef __BORLANDC__#include <stdio.h>#else#include <cstdio>#endif#include "private.h"#ifdef CCXX_HAVE_NEW_INIT#include <new>#elseinline void* operator new(size_t s,void* p){ return p;}#endif#ifdef WIN32#include <process.h>#endif#ifdef CCXX_NAMESPACESnamespace ost {#endif#ifdef _THR_UNIXWARE#undef _POSIX_THREAD_PRIORITY_SCHEDULING#define sigwait(x, y) _thr_sigwait(x, y)#endif#ifdef __linux__#define CCXX_SIG_THREAD_ALARM// NOTE: Comment this line to test Resume/Signal using one signal method#define CCXX_SIG_THREAD_STOPCONT#endif#ifndef WIN32typedef void *(*exec_t)(void *);typedef RETSIGTYPE (*signalexec_t)(int);extern "C"{#ifndef CCXX_SIG_THREAD_STOPCONT#ifndef _THR_SUNOS5#ifndef HAVE_PTHREAD_SUSPENDstatic RETSIGTYPE ccxx_sigsuspend(int);#endif#endif#endifstatic void ccxx_exec_handler(Thread *th);static void ccxx_thread_cleanup(void* arg);static void ccxx_thread_destructor(void* arg);static void ccxx_sig_handler(int signo);}#endif // ndef WIN32#ifdef CCXX_SIG_THREAD_CANCELextern "C" RETSIGTYPE _th_sigcancel(int sig){ pthread_exit(NULL);}#endif#ifdef WIN32typedef unsigned (__stdcall *exec_t)(void *);#ifndef CCXX_NO_DLL# if defined(_MSC_VER) && !defined(_DLL)# error This project cannot be compiled as a static library. Some implementation stuff require DLL# endif#endif // CCXX_NO_DLL#endif // WIN32/* * Start Suspend/Resume stuff */// method to suspend are// - system suspend/resume recursive// - system suspend/resume not recursive// - one signal only, not recursive#ifndef WIN32#define CCXX_SUSPEND_MODE_RECURSIVE 1#define CCXX_SUSPEND_MODE_NOT_RECURSIVE 2#define CCXX_SUSPEND_MODE_ONE_SIGNAL 3#define CCXX_SUSPEND_MODE_MACH 4#if defined(_THR_MACH) && !defined(MACOSX)#define CCXX_SUSPEND_MODE CCXX_SUSPEND_MODE_MACH#elif defined(HAVE_PTHREAD_SUSPEND)#define CCXX_SUSPEND_MODE CCXX_SUSPEND_MODE_NOT_RECURSIVEstatic inline void ccxx_resume(cctid_t tid) { pthread_continue(tid); }static inline void ccxx_suspend(cctid_t tid) { pthread_suspend(tid); }#else# if defined(_THR_SUNOS5) || defined(CCXX_SIG_THREAD_STOPCONT)# define CCXX_SUSPEND_MODE CCXX_SUSPEND_MODE_NOT_RECURSIVE# ifdef _THR_SUNOS5 static inline void ccxx_resume(cctid_t tid) { thr_continue((thread_t)tid); } static inline void ccxx_suspend(cctid_t tid) { thr_suspend((thread_t)tid); }# else# define CCXX_SIG_THREAD_SUSPEND SIGSTOP# define CCXX_SIG_THREAD_RESUME SIGCONT static inline void ccxx_resume(cctid_t tid) { pthread_kill(tid, CCXX_SIG_THREAD_RESUME); } static inline void ccxx_suspend(cctid_t tid) { pthread_kill(tid, CCXX_SIG_THREAD_SUSPEND); }# endif# else# define CCXX_SUSPEND_MODE CCXX_SUSPEND_MODE_ONE_SIGNAL# ifndef SIGUSR3# ifdef SIGWINCH# define SIGUSR3 SIGWINCH# else# define SIGUSR3 SIGINT# endif# endif# define CCXX_SIG_THREAD_SUSPEND SIGUSR3# define CCXX_SIG_THREAD_RESUME SIGUSR3 static inline void ccxx_resume(cctid_t tid) { pthread_kill(tid, CCXX_SIG_THREAD_RESUME); } static inline void ccxx_suspend(cctid_t tid) { pthread_kill(tid, CCXX_SIG_THREAD_SUSPEND); }# endif#endif#endif // ndef WIN32Thread::Cancel Thread::enterCancel(void){ Thread *th = getThread(); if(!th) return cancelInitial; Cancel old = th->_cancel; if(old != cancelDisabled && old != cancelImmediate) { th->setCancel(cancelImmediate);#ifdef WIN32 Thread::yield();#else pthread_testcancel();#endif } return old;}void Thread::exitCancel(Cancel old){ Thread *th = getThread(); if(!th) return; if(old != th->_cancel) {#ifndef WIN32 pthread_testcancel();#endif th->setCancel(old); }}void Thread::suspend(void){ if(!priv) return;#ifdef WIN32 if (!priv->_active || !priv->_suspendEnable) {#ifdef CCXX_EXCEPTIONS if (Thread::getException() != throwNothing) throw this;#endif return; } SuspendThread(priv->_hThread);#else if (!priv->_suspendEnable) return;#if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_MACH thread_suspend(priv->_mach);#endif#if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_RECURSIVE ccxx_suspend(priv->_tid);#endif#if (CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_NOT_RECURSIVE) \ || (CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_ONE_SIGNAL) if (++priv->_suspendcount != 1) return; ccxx_suspend(priv->_tid);#endif#endif // WIN32}#if defined(__FreeBSD__)#define AUTOSTACK 0x10000#endif#if defined(MACOSX)#define AUTOSTACK 0#endif#ifndef AUTOSTACK#define AUTOSTACK 0x100000#endifsize_t Thread::_autostack = AUTOSTACK;void Thread::resume(void){ if(!priv) return;#ifdef WIN32 if (!priv->_active || !priv->_suspendEnable) {#ifdef CCXX_EXCEPTIONS if (Thread::getException() != throwNothing) throw this;#endif return; } ResumeThread(priv->_hThread);#else if (!priv->_suspendEnable) return;#if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_MACH thread_resume(priv->_mach);#endif#if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_RECURSIVE ccxx_resume(priv->_tid);#endif#if (CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_NOT_RECURSIVE) \ || (CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_ONE_SIGNAL) int c; if ( (c = --priv->_suspendcount) > 0) return; if ( c < 0 ) { ++priv->_suspendcount; return; } ccxx_resume(priv->_tid);#endif#endif // WIN32}void Thread::join(void){ bool detached = isDetached(); joinSem.wait(); if(detached) { joinSem.post(); return; }#ifdef WIN32 // wait for real w32 thread to cleanup if(priv->_hThread) { WaitForSingleObject(priv->_hThread, INFINITE); ::CloseHandle(priv->_hThread); priv->_hThread = NULL; } #else // make sure we cleanup exiting thread if(priv->_jtid) { pthread_join(priv->_jtid, NULL); } priv->_jtid = 0;#endif joinSem.post(); // enable next waiting thread after cleanup}#ifndef WIN32#if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_ONE_SIGNAL// NOTE: Do not modify _suspendcount here, one program can call// Suspend 2 or more time but this function can be called only onceinline RETSIGTYPE ThreadImpl::ThreadSigSuspend(int){ sigset_t sigs; sigemptyset(&sigs); sigaddset(&sigs, SIGUSR3); while ( (getThread()->priv->_suspendcount) > 0) {#ifdef HAVE_SIGWAIT2 int signo; sigwait(&sigs, &signo);#else sigwait(&sigs);#endif }}static RETSIGTYPE ccxx_sigsuspend(int signo){ return ThreadImpl::ThreadSigSuspend(signo);}#endifvoid Thread::setSuspend(Suspend mode){ if(!priv) return; priv->_suspendEnable = (mode == suspendEnable);#ifndef HAVE_PTHREAD_SUSPEND#ifdef CCXX_SIG_THREAD_SUSPEND sigset_t mask; sigemptyset(&mask); sigaddset(&mask, CCXX_SIG_THREAD_SUSPEND); switch(mode) { case suspendEnable: pthread_sigmask(SIG_UNBLOCK, &mask, NULL); return; case suspendDisable: pthread_sigmask(SIG_BLOCK, &mask, NULL); }#endif#endif}/* * End Suspend/Resume stuff */static sigset_t *blocked_signals(sigset_t *sig){ sigemptyset(sig); sigaddset(sig, SIGINT); sigaddset(sig, SIGKILL); sigaddset(sig, SIGHUP); sigaddset(sig, SIGABRT); sigaddset(sig, SIGALRM); sigaddset(sig, SIGPIPE);#if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_ONE_SIGNAL sigaddset(sig, SIGUSR3);#endif return sig;}#endif // ndef WIN32typedef enum ThreadType { threadTypeNormal=0, threadTypeMain, threadTypePosix, threadTypeDummy} ThreadType;class MainThread : public Thread{protected: void run(void) {return;};#ifndef WIN32 void onSignal(int signo) { std::exit(signo);};#endifpublic: MainThread() : Thread(true) {};};// mantain info on thread creationclass DummyThread : public Thread{protected: void run() {};public: DummyThread() : Thread(false) { priv->_type = threadTypeDummy; }#ifdef WIN32 static void CheckDelete();#endif};#ifdef WIN32static ThreadKey _self;#else// NOTE: _self instantiation MUST appear before _mainthread !!ThreadKey ThreadImpl::_self(ccxx_thread_destructor);#endif#ifdef WIN32void DummyThread::CheckDelete(){ Thread *th = (Thread*)_self.getKey(); if (!th) return; // delete if dummy thread if (th->priv->_type == threadTypeDummy) delete th;}#endifstatic MainThread _mainthread;Thread *Thread::_main = NULL;// invalid pointer to thread used to test deleted thread// point in the middle of mainthread...#define DUMMY_INVALID_THREAD ((Thread*)(((char*)((Thread*)&_mainthread))+1))#if !defined(WIN32)#ifndef CCXX_SIG_THREAD_ALARMPosixThread *PosixThread::_timer = NULL;Mutex PosixThread::_arm;#endif#endif//void PosixThread::sigInstall(int);Thread::Thread(bool isMain):_cancel(cancelDefault), _start(NULL), priv(new ThreadImpl(threadTypeDummy)){#ifdef WIN32 priv->_tid = GetCurrentThreadId(); // FIXME: error handling HANDLE process = GetCurrentProcess(); DuplicateHandle(process,GetCurrentThread(),process,&priv->_hThread,0,FALSE,DUPLICATE_SAME_ACCESS); _parent = this; priv->_cancellation = CreateEvent(NULL, TRUE, FALSE, NULL); if(isMain) { setName("main()"); priv->_type = threadTypeMain; _main = this; } else setName("-dummy-"); _self.setKey(this);#else priv->_suspendEnable = false; priv->_tid = pthread_self(); _parent = NULL; struct sigaction act; // NOTE: for race condition (signal handler can use getThread) // you should initialize _main and _self before registering signals ThreadImpl::_self.setKey(this); if(isMain == true) { _main = this; priv->_type = threadTypeMain;#if !defined(__CYGWIN32__) && !defined(__MINGW32__) PosixThread::sigInstall(SIGHUP); PosixThread::sigInstall(SIGALRM); PosixThread::sigInstall(SIGPIPE); PosixThread::sigInstall(SIGABRT); memset(&act, sizeof(act), 0); act.sa_handler = (signalexec_t)&ccxx_sig_handler; sigemptyset(&act.sa_mask);# ifdef SA_RESTART act.sa_flags = SA_RESTART;# else act.sa_flags = 0;# endif# ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT;# endif# ifdef SIGPOLL sigaction(SIGPOLL, &act, NULL);# else sigaction(SIGIO, &act, NULL);# endif # if CCXX_SUSPEND_MODE == CCXX_SUSPEND_MODE_ONE_SIGNAL act.sa_handler = ccxx_sigsuspend; sigemptyset(&act.sa_mask);# ifdef SA_RESTART act.sa_flags = SA_RESTART;# else act.sa_flags = 0;# endif sigaction(SIGUSR3, &act, NULL);# endif# ifdef CCXX_SIG_THREAD_CANCEL memset(&act, sizeof(act), 0); act.sa_flags = 0; act.sa_handler = _th_sigcancel; sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask, SIGHUP); sigaddset(&act.sa_mask, SIGALRM); sigaddset(&act.sa_mask, SIGPIPE); sigaction(CCXX_SIG_THREAD_CANCEL, &act, NULL);# endif#endif }#endif // WIN32} Thread::Thread(int pri, size_t stack):_cancel(cancelDefault), _start(NULL), priv(new ThreadImpl(threadTypeNormal)){#ifdef WIN32 if(!_main) { _self.setKey(NULL); _main = this; setName("main()"); } else#ifdef WIN32 _name[0] = 0;#else snprintf(_name, sizeof(_name), "%d", getId());#endif _parent = Thread::get(); if(_parent) priv->_throw = _parent->priv->_throw; else _parent = this; priv->_cancellation = CreateEvent(NULL, TRUE, FALSE, NULL); if(!priv->_cancellation) THROW(this); if(stack <= _autostack) priv->_stack = 0; else priv->_stack = stack; if(pri > 2) pri = 2; if(pri < -2) pri = -2; switch(pri) { case 1: priv->_priority = THREAD_PRIORITY_ABOVE_NORMAL; break; case -1: priv->_priority = THREAD_PRIORITY_BELOW_NORMAL; break; case 2: priv->_priority = THREAD_PRIORITY_HIGHEST; break; case -2: priv->_priority = THREAD_PRIORITY_LOWEST; break; default: priv->_priority = THREAD_PRIORITY_NORMAL; }#else int salign; pthread_attr_init(&priv->_attr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -