📄 wy_thread.cpp
字号:
/* Copyright is licensed under GNU LGPL. by I.J.Wang 2003.active_threads()=1General error, chk_thread2.cpp(329)pass: 24,2,11,20,11,16,17,2,4程式記憶體區段錯誤 ./chk_thread2pass:24,3,2reset halt:pass: 5,23,10,2,9,4,4,3,5,18,1,1,6,3,6*/#define WYLIB_SOURCE#include "wy_thread.h"#include <pthread.h>#include <new> // bad_alloc#ifdef WY_DEBUG#include "wy_uty.h"#endifconst char Wy_Thread::class_name[]="Wy_Thread";// Because no document found for the value of ::pthread_t for no thread.// pick 0 for it, so far so good (the value it is initialized does not work)//static const ::pthread_t TID_NoThread=0;const ::pthread_t Wy_ThreadID::Default_ThreadID=TID_NoThread;Wy_ThreadID::Wy_ThreadID() WY__TSPC() : _tid(Default_ThreadID) {};Wy_ThreadID::Wy_ThreadID(const Wy_ThreadID& src) WY__TSPC() : _tid(src._tid) {}; Wy_ThreadID::Wy_ThreadID(::pthread_t tid) WY__TSPC() : _tid(tid) {};Wy_ThreadID::Wy_ThreadID(Wy_ThreadID& src, Wy::ByMove_t) WY__TSPC() : _tid(src._tid){};::pthread_t Wy_ThreadID::_pthread_id(void) const WY__TSPC(){ return _tid; };bool Wy_ThreadID::is_default(void) const WY__TSPC(){ return _tid==Default_ThreadID; };void Wy_ThreadID::reset(void) WY__TSPC(){ _tid=Default_ThreadID; };void Wy_ThreadID::reset(const Wy_ThreadID& src) WY__TSPC(){ _tid=src._tid; };void Wy_ThreadID::reset(::pthread_t tid) WY__TSPC(){ _tid=tid;};const Wy_ThreadID& Wy_ThreadID::operator =(const Wy_ThreadID& tid) WY__TSPC(){ _tid=tid._tid; return(*this); };bool Wy_ThreadID::operator==(Wy_ThreadID id) const WY__TSPC(){ return _tid==id._tid; };bool Wy_ThreadID::operator!=(Wy_ThreadID id) const WY__TSPC(){ return _tid!=id._tid; };bool Wy_ThreadID::_thread_equal(Wy_ThreadID t1, Wy_ThreadID t2) WY__TSPC(){ return ::pthread_equal(t1._tid,t2._tid); };//-----------------------------------------------------------------static ::pthread_once_t wy__toltab_once_var=PTHREAD_ONCE_INIT;// [Internal] Array item of Wy__TOLTab// Pair of Wy_ThreadID and Wy_Thread object pointer for association//// Note: The association should be 1-1, or result not predictable//class Wy__TOLItem { public: // [Syn] construct default object // // tol_ptr() = NULL // tol_tid() = Wy_ThreadID() // inline Wy__TOLItem() WY__NOTHROW__ : _tid(),_optr(NULL) {}; inline Wy__TOLItem(const Wy__TOLItem& src) WY__NOTHROW__ : _tid(src._tid),_optr(src._optr) {}; inline Wy__TOLItem(Wy_ThreadID id, const Wy_Thread* optr) WY__NOTHROW__ : _tid(id),_optr(optr) {}; inline void reset(void) WY__NOTHROW__ { _tid.reset(); _optr=NULL; }; inline void reset(const Wy__TOLItem& src) WY__NOTHROW__ { _tid.reset(src._tid); _optr=src._optr; }; // self-ops ok inline void reset(Wy_ThreadID id, const Wy_Thread* optr) WY__NOTHROW__ { _tid.reset(id); _optr=optr; }; inline bool is_default(void) const WY__NOTHROW__ { return _optr==NULL; }; inline const Wy_Thread* tol_ptr(void) const WY__NOTHROW__ { return _optr; }; inline Wy_ThreadID tol_tid(void) const WY__NOTHROW__ { return _tid; }; private: Wy_ThreadID _tid; const Wy_Thread* _optr;};// [Internal] class of set of Wy__TOL //// Note: Exactly one instance(wy__toltab_ptr) of this class is declared//// Note: All member access should acquire the lock first//class Wy__TOLTab { size_t _find_idx(Wy_ThreadID tid) WY__NOTHROW__ { size_t i=0; for( ; (i<_tabsize)&&(_tab[i].tol_tid()!=tid); ++i) { // value cmp }; return(i); }; public: Wy__TOLTab() WY__NOTHROW__ : _tabsize(0) {}; // [Syn] Get mutex of *this // // [Ret] reply // WyMutex& mutex(void) WY__NOTHROW__ { return _mtx; }; // [Syn] Get the number of entries // // [Ret] number of Wy__TOL entries *this is handling // size_t size(void) const WY__NOTHROW__ { return _tabsize; }; // [Syn] Add entry<Wy_Thread pointer,Wy_ThreadID> // // Note: 0. tid is used as the key // 1. tid must be equal to optr->thread_id() // (this member does not dereference optr) // // [Ret] Ok entry added // Wym_EEXIST tid already in *this // Wym_FAULT optr is NULL // Wym_ENOSPC maximal number of threads reached // WyRet add(const Wy_Thread* optr,Wy_ThreadID tid) { if(optr==NULL) { return(Wym_EINVAL); } if(this->_find_idx(tid)<_tabsize) { WY_RETURN( Wym_EEXIST ); } if(_tabsize>=Wy_Thread::Max_Threads) { WY_RETURN(Wym_ENOSPC); } _tab[_tabsize++].reset(tid,optr); return(Ok); }; // [Syn] Remove the entry whose Wy_ThreadID is identical to tid // If no entry (tid,*) in *this, no effect. // bool remove(Wy_ThreadID tid) WY__NOTHROW__ { const size_t i( this->_find_idx(tid) ); if(i>=_tabsize) { return(false); // tid not in tab } _tabsize--; _tab[i].reset(_tab[_tabsize]); return(true); }; // [Syn] Find entry whose Wy_ThreadID is identical to tid // and return the Wy_Thread* associates with it // // [Ret] The Wy_Thread* associates with tid // NULL, if no item found // const Wy_Thread* find(Wy_ThreadID tid) WY__NOTHROW__ { const size_t i( this->_find_idx(tid) ); if(i>=_tabsize) { return(NULL); // tid not in tab } return _tab[i].tol_ptr(); }; private: Wy__TOLItem _tab[Wy_Thread::Max_Threads]; size_t _tabsize; mutable WyMutex _mtx;} static *wy__toltab_ptr=NULL;extern "C" void wy__toltab_once_func(void){ try { wy__toltab_ptr= new Wy__TOLTab(); // note: never free'd } catch(...) { WY_TERMINATE(""); };};WyStr Wy::wrd(const Wy_ThreadID& tid)try { WyStr v("TID_"); // describe Wy_ThreadID in hexidecimal number WyRet r=Wy::_catstr(v,(unsigned)tid._pthread_id(),16); if(r!=Ok) { WY_THROW( WyStr::Reply(r) ); } return(v); }catch(const WyStr::Reply& e) { if(e==Wym_ENOMEM) { throw; } WY_THROW( WyRet(e) );};//------------------------------------------------------------------------------#ifdef WY_DEBUG size_t wy_joined_cnt=0; size_t wy_created_cnt=0; size_t wy_act_max=0; WyMutex wy_act_mutex;#endif// tid of main (program startup thread)//const Wy_ThreadID Wy_Thread::wy_main_thrd_id(::pthread_self());::pthread_once_t wy__thread_once_var=PTHREAD_ONCE_INIT;bool Wy_Thread::set_cancelable(bool en){ int oldstate; const int v(::pthread_setcancelstate( en? PTHREAD_CANCEL_ENABLE: PTHREAD_CANCEL_DISABLE , &oldstate)); if(v!=0) { // man. says only parameter error. which should not happen. WY_THROW( WyRet(v) ); } return (oldstate==PTHREAD_CANCEL_ENABLE);};Wy_Thread::CancelType Wy_Thread::set_canceltype(CancelType ct){ int oldtype; const int v(::pthread_setcanceltype(ct,&oldtype)); if(v!=0) { // man. says only parameter error. which should not happen. WY_THROW( WyRet(v) ); } return(static_cast<CancelType>(oldtype));};extern "C" void wy__thread_once_func(void) WY__TSPC(){ // intended for feature test code, nothing yet.};inline void Wy_Thread::_non_cancellable(void) WY__TSPC(){ if(::pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL)!=0) { WY_TERMINATE(""); }};// [Syn] Cancel an Active thread and wait for non-Active state//// post: thread state is Null or Stopped (no active thread)//void Wy_Thread::_cleanup_thread(WyLock& aa){ WyRet r; // Cancel the possibly active thread, and join the thread // if(_thrd_stat==Active) { // Note: Wait forever if the threead is not cancellable. // do { int v; while((v=::pthread_cancel(_thrd_id))!=0) { // ref. note5 if(v==EAGAIN) { Wy__Base::yield(); // probably ok continue; } // ESRCH or others not documented Wy__Base::put_abnmsg( WyReply(v)->c_repstr() ,__FILE__,__LINE__); Wy__Base::terminate(); }; // cancel_point if((r=_thrd_stat_cond.wait(aa))!=Ok) { WY_THROW(r); // Wym_EINVAL } } while(_thrd_stat==Active); } else if(_thrd_stat==Stopped) { } else { // Null (no thread) };};// [Spc] Wy_Thread relies on pthread. Default thread attributes are://// detatchstate= PTHREAD_CREATE_DETATCHED// schedpolicy = SCHED_OTHER (regular, non-realtime)// schedparam = 0// inheritsched= PTHREAD_EXPLICIT_SCHED// scope = PTHREAD_SCOPE_SYSTEM//Wy_Thread::Wy_Thread()try : _thrd_stat_cond(), _thrd_stat(Null), _thrd_id(Wy_ThreadID::Default_ThreadID), _exit_obj(), _in_destroy(false), _mtx(){ ::pthread_once(&wy__toltab_once_var, wy__toltab_once_func); ::pthread_once(&wy__thread_once_var, wy__thread_once_func); WyLock aa(_mtx); int v; if((v=::pthread_attr_init(&_thrd_attr))!=0) { // // manu says only ENOMEM, linux man just says errno. // WY_THROW( Reply(v) ); } if((v=::pthread_attr_setdetachstate(&_thrd_attr,PTHREAD_CREATE_DETACHED))!=0) { // man. indicates only EINVAL WY_THROW( WyRet(v) ); }}catch(const Wy_Thread::Reply&) { throw;}catch(const WyLock::Reply& e) { WY_THROW( WyRet(e) );}catch(const WyRet& e) { WY_THROW( WyRet(e) );};Wy_Thread::~Wy_Thread() WY__TSPC()try { // Wy_Thread destructor is non-cancelable // Because the active thread need to access *this // _non_cancellable(); WyLock aa(_mtx); WyRet r; if(_in_destroy==true) { WY_TERMINATE(""); // destroy twice } _in_destroy=true; this->_cleanup_thread(aa); // Cleanup members that need cleanup // const int v=::pthread_attr_destroy(&_thrd_attr); if(v!=0) { // manu says only EINVAL could happen Wy__Base::put_abnmsg( WyReply(v)->c_repstr() ,__FILE__,__LINE__); Wy__Base::terminate(); }}catch(const WyLock::Reply& e) { Wy__Base::put_abnmsg( e->c_repstr() ,__FILE__,__LINE__); Wy__Base::terminate();}catch(const WyRet& e) { Wy__Base::put_abnmsg( e->c_repstr() ,__FILE__,__LINE__); Wy__Base::terminate();}catch(const std::exception&) { WY_TERMINATE("");}catch(...) { WY_TERMINATE("");};bool Wy_Thread::is_default(void) consttry { // // _thrd_stat==Null ensures the default state, including // // 1. _thrd_id==Wy_ThreadID::Default_ThreadID // 2. _exit_obj.is_default() // 3. _in_destroy==false // 4. _thrd_attr is default // WyLock aa(_mtx); return(_thrd_stat==Null);}catch(const WyLock::Reply& e) {#ifdef WY_DEBUG Wy::cerr << Wy::wrd(e) << '\n';#endif WY_THROW( WyRet(e) );}catch(const WyRet& e) {#ifdef WY_DEBUG Wy::cerr << Wy::wrd(e) << '\n';#endif WY_THROW( WyRet(e) );};// [Non-cancellation Point]Wy_ThreadID Wy_Thread::thread_id(void) consttry { WyLock aa(_mtx); return Wy_ThreadID(_thrd_id); }catch(const WyLock::Reply& e) {#ifdef WY_DEBUG Wy::cerr << Wy::wrd(e) << '\n';#endif WY_THROW( WyRet(e) );}catch(const WyRet& e) {#ifdef WY_DEBUG Wy::cerr << Wy::wrd(e) << '\n';#endif WY_THROW( WyRet(e) );};// [Non-cancellation Point]Wy_Thread::ThreadState Wy_Thread::thread_state(void)try { WyLock aa(_mtx); if(_thrd_stat==Active) { if(::pthread_equal(_thrd_id,::pthread_self())) { WY_THROW( Reply(Wym_EPERM) ); // thread can not query it state } } return _thrd_stat;}catch(const Wy_Thread::Reply&) { throw;}catch(const WyLock::Reply& e) {#ifdef WY_DEBUG Wy::cerr << Wy::wrd(e) << '\n';#endif WY_THROW( WyRet(e) );}catch(const WyRet& e) {#ifdef WY_DEBUG Wy::cerr << Wy::wrd(e) << '\n';#endif WY_THROW( WyRet(e) );};// [Non-cancellation Point]WyRet Wy_Thread::exitcode(void) consttry { WyLock aa(_mtx); return(_exit_obj);}catch(const WyLock::Reply& e) {#ifdef WY_DEBUG Wy::cerr << Wy::wrd(e) << '\n';#endif WY_THROW( WyRet(e) );}catch(const WyRet& e) {#ifdef WY_DEBUG Wy::cerr << Wy::wrd(e) << '\n';#endif WY_THROW( WyRet(e) );};// [Non-cancellation Point]WyRet Wy_Thread::reset(void)try { NoCancel noc; WyLock aa(_mtx); if(_in_destroy==true) { WY_THROW( WyRet() ); } WyRet r; // If the created thread is active(running), cancel it. // if(_thrd_stat==Active) { if(::pthread_equal(_thrd_id,::pthread_self())) { // thread (tmain) is not allowed to reset itself // rule of libwy says reset() always returns with default object // WY_THROW( WyRet() ); } this->_cleanup_thread(aa); } int v; // Reset thread attr object (destoy and initialize again) //
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -