📄 chk_thread2.cpp
字号:
/* Copyright is licensed under GNU LGPL. by I.J.Wang 2006 Test Wy_Thread Part-2: cancellation test Build: make chk_thread2 Warning: This check does not get Ok result (chk_thread1 is Ok)*/#include "wy_thread.h"#include "wy_uty.h"#include "wytimespec.h"#include "wyregfile.h"#include "wychrfile.h"#include <exception> // for set_terminate#include <cstdlib>#if WY_THREAD_VERSION!=31#error Test code is for WY_THREAD_VERSION 31#endiftypedef void (*PFV)(void);// Each thread begun increases ent_cnt by one//static int ent_cnt=0;static size_t peak_threads=0;static WyMutex ent_cnt_mtx;// Each thread exits increases lft_cnt by one//static int lft_cnt=0; static WyMutex lft_cnt_mtx;// Max. fd measuredstatic int peak_fd=0;static WyMutex fd_cnt_mtx;static void term_msg(void){ Wy::cerr << "term_msg entered\n";};static void unexp_msg(void){ Wy::cerr << "unexp_msg entered\n"; try { throw; } catch(const WyRet& e) { Wy::cerr << Wy::wrd(e) << '\n'; //throw; };};// The thread class to run the test//class TestThread2 : public Wy_Thread { int _lev; // level, 0<=terminal node int _nid; WyMutex t2_mtx; void tmain_enter(void) { WyMutex::lock(ent_cnt_mtx); ++ent_cnt; const size_t tt=Wy_Thread::active_threads(); if(tt>peak_threads) { peak_threads=tt; } WyMutex::unlock(ent_cnt_mtx); }; void tmain_leave(void) { WyMutex::lock(lft_cnt_mtx); ++lft_cnt; WyMutex::unlock(lft_cnt_mtx); }; void tmain_t1(void); void tmain_t2(void); protected: virtual WyRet tmain(void); public: // Construct object ready to run the thread with specified exit type and code // TestThread2() : Wy_Thread() , _lev(0), _nid(-1) {}; ~TestThread2() throw(); WyRet begin(int id, int level) { WyRet r; { WyLock aa(t2_mtx); // lock data members (for test) _nid=id; _lev=level; r=Wy_Thread::begin(); } return(r); };};TestThread2::~TestThread2() throw()try { Wy_Thread::tmain_close(); Wy_Thread::tmain_close(); // simulate multi-layer (should be trival effect)}catch(const WyRet& e) { Wy::cerr << Wy::wrd(e) << '\n'; throw;}catch(...) { Wy::cerr << "~TestThread2()\n"; throw;};WyRet TestThread2::tmain(void)try { //std::set_terminate(unexp_msg); causing long dump //std::set_unexpected(term_msg); tmain_enter(); if(thread_self().is_default()) { WY_TERMINATE(""); } { TestThread2 *tptr=dynamic_cast<TestThread2*>( tbase_ptr() ); if(tptr==NULL) { WY_TERMINATE(""); } if(tptr!=dynamic_cast<TestThread2*>(this)) { Wy::cerr << "tbase_ptr()=" << tbase_ptr() << ", this=" << this << '\n'; WY_TERMINATE(""); } WyLock aa(t2_mtx); if((tptr->_nid!=_nid)||(tptr->_lev!=_lev)) { Wy::cerr << "main_thread_id()=" << wy_main_thrd_id._pthread_id() << '\n'; Wy::cerr << "\nthread_self()=" << ::pthread_self() << '\n'; Wy::cerr << "tptr: _nid=" << tptr->_nid << ", " << " _lev=" << tptr->_lev << ", thread_id()=" << tptr->thread_id()._pthread_id() << '\n'; Wy::cerr << "this: _nid=" << this->_nid << ", " << " _lev=" << this->_lev << ", thread_id()=" << this->thread_id()._pthread_id() << '\n'; WY_TERMINATE(""); } } // make child thread of the next level // TestThread2 child; { WyLock aa(t2_mtx); if(_lev>0) { WyRet r( child.begin(_nid*10,_lev-1) ); if(r!=Ok) { WY_THROW(r); } } } // loop to make the test code consume more time // for(int i=0; i<50; ++i) { //Wy::sleep( WyTimeSpec(0,2000000) ); tmain_t1(); tmain_t2(); } tmain_leave(); return(Ok);}catch(const WyRet& e) { Wy::cerr << Wy::wrd(e) << '\n'; tmain_leave(); return(e);}catch(...) { tmain_leave(); throw;};// use rdonly functions that are cancellation points//void TestThread2::tmain_t1(void)try { const WyCSeg FData="/* Copyright is licensed under GNU LGPL. by I.J.Wang 2006\n"; WyRet r; WyRegFile tfile(__FILE__,O_RDONLY); WyStr str; size_t n_rd; WyMutex::lock(fd_cnt_mtx); if(tfile.fh().fd()>peak_fd) { peak_fd=tfile.fh().fd(); } WyMutex::unlock(fd_cnt_mtx); //tfile.set_pos(0); if((r=tfile.read(str,FData.size(),n_rd))!=Ok) { Wy::cerr << Wy::wrd(r) << '\n'; } if(n_rd!=str.size()) { WY_TERMINATE(""); } if(n_rd!=FData.size()) { WY_TERMINATE(""); } if(str!=FData) { WY_TERMINATE(""); } // reset if((r=tfile.reset(__FILE__,O_RDONLY))!=Ok) { WY_THROW(r); } // read(void*,size_t,size_t&) n_rd=0; if((r=tfile.read(&str[0],FData.size(),n_rd))!=Ok) { Wy::cerr << Wy::wrd(r) << '\n'; } if(n_rd!=FData.size()) { WY_TERMINATE(""); } str._setsize(n_rd); if(str!=FData) { WY_TERMINATE(""); } // _read_till tfile.set_pos(0); str.reset(); n_rd=0; if((r=tfile._read_till(str,FData.size(),n_rd,'\n'))!=Ok) { Wy::cerr << Wy::wrd(r) << '\n'; } if(n_rd!=str.size()) { WY_TERMINATE(""); } if(n_rd!=FData.size()) { WY_TERMINATE(""); } if(str!=FData) { WY_TERMINATE(""); } // Wy::full_read tfile.set_pos(0); str.reset(); n_rd=0; if((r=Wy::full_read(tfile,str,FData.size()))!=Ok) { Wy::cerr << Wy::wrd(r) << '\n'; } if(str!=FData) { WY_TERMINATE(""); } // This functions are just for cancellation point test Wy::sleep( WyTimeSpec(0,1) );}catch(const WyRet& e) { Wy::cerr << Wy::wrd(e) << '\n'; throw;}catch(...) { #ifdef WY_DEBUG Wy::cerr << "t1 "; #endif throw;};// write to /dev/null//void TestThread2::tmain_t2(void)try { WyByteFlow bf("/dev/null",O_WRONLY); WyRet r; size_t n_wr; WyMutex::lock(fd_cnt_mtx); if(bf.fh().fd()>peak_fd) { peak_fd=bf.fh().fd(); } WyMutex::unlock(fd_cnt_mtx); if((r=bf.write(&r,sizeof(r),n_wr))!=Ok) { Wy::cerr << Wy::wrd(r) << '\n'; } if((r=bf._tcdrain())!=Ok) { } // strnum/WyTimeSpec { WyTimeSpec tm1("1.234e2"); WyTimeSpec tm2(123,400000000LL); if(tm1!=tm2) { WY_THROW( WyRet() ); } tm1.reset(); tm2.reset(); }}catch(const WyRet& e) { Wy::cerr << Wy::wrd(e) << '\n'; throw;}catch(...) { #ifdef WY_DEBUG Wy::cerr << "t2 "; #endif throw;};// Check default thread object properties//static WyRet chk_default_attr(TestThread2& thrd){ WyRet r; if(thrd.is_default()==false) { WY_RETURN(Wym_E127); } if(thrd.thread_state()!=Wy_Thread::Null) { WY_RETURN(Wym_E127); } if((r=thrd.wait_not(Wy_Thread::Active))!=Ok) { WY_RETURN(Wym_E127); } if((r=thrd.wait_not(Wy_Thread::Stopped))!=Ok) { WY_RETURN(Wym_E127); } if(!thrd.exitcode().is_default()) { WY_RETURN(Wym_E127); } return(Ok);};// Test in Tight Loop//static void t_tight_loop(void){ const int NumOfThrds=50; // 300 would get ENOMEM on my playform const int LoopCount=10000; TestThread2 thrTab[NumOfThrds]; WyRet r; // Check all thread objects in thrTab[] are default // for(int i=0; i<NumOfThrds; ++i) { if((r=chk_default_attr(thrTab[i]))!=Ok) { WY_THROW(r); } } // The tight loop create/cancel an entry in thrTab[] by random hit // Wy::cout << "count=" << LoopCount << " ...wait\n"; //std::srand( Wy::now().nano() ); for(int cnt=0; cnt<LoopCount; ++cnt) { if((cnt%(LoopCount/75))==0) { Wy::cout << '.'; } // notify alive Wy::sleep( WyTimeSpec(0,500000) ); // sleep 0.5 mS // Generate random index for each loop const int idx=(int)(((NumOfThrds-0.1)*std::rand())/(double)RAND_MAX); #ifdef WY_DEBUG Wy::cerr << ' ' << idx; #endif TestThread2& thrd=thrTab[idx]; switch(thrd.thread_state()) { case Wy_Thread::Stopped: #ifdef WY_DEBUG Wy::cerr << 's'; #endif if((r=thrd.reset())!=Ok) { // bring to Null state WY_THROW(r); } break; case Wy_Thread::Null: // Create a thread if the entry is in Null state // #ifdef WY_DEBUG Wy::cerr << 'B'; #endif while((r=thrd.begin(idx,1))!=Ok) { if(r==Wym_EAGAIN) { continue; } WY_THROW(r); } break; case Wy_Thread::Active: // Cancel the thread // (note: the thread may have terminated) // #ifdef WY_DEBUG Wy::cerr << 'C'; #endif thrd.cancel(); break; default: WY_THROW( WyRet() ); // should not get here } } #ifdef WY_DEBUG Wy::cerr << "\nloop end\n"; #endif/* { // print statistics before reset WyLock a1(ent_cnt_mtx); WyLock a2(lft_cnt_mtx); WyLock a3(fd_cnt_mtx); Wy::cerr << "\nent=" << ent_cnt << ", lft=" << lft_cnt << '\n'; Wy::cout << "max_threads()= " << Wy_Thread::max_threads() << '\n'; Wy::cout << "maximal testing threads= " << peak_threads << '\n'; Wy::cout << "maximal measured fd= " << peak_fd << '\n'; }*/ for(int i=0; i<NumOfThrds; ++i) { #ifdef WY_DEBUG Wy::cerr << ' ' << i; #endif thrTab[i].reset(); } while(Wy_Thread::active_threads()!=0) { // should be no more active thread Wy::cerr << " active_threads()=" << Wy_Thread::active_threads() << '\n'; WY_THROW( WyRet() ); } { // print statistics WyLock a1(ent_cnt_mtx); WyLock a2(lft_cnt_mtx); WyLock a3(fd_cnt_mtx); Wy::cout << "\nent=" << ent_cnt << ", lft=" << lft_cnt << '\n'; Wy::cout << "max_threads()= " << Wy_Thread::max_threads() << '\n'; Wy::cout << "maximal testing threads= " << peak_threads << '\n'; Wy::cout << "maximal measured fd= " << peak_fd << '\n'; }};int main(void)try { Wy::cout << "Checking wy_thread.cpp, tight loop. "; t_tight_loop(); Wy::cout << "Checked Ok\n"; return(0);}catch(const WyRet& e) { Wy::cerr << Wy::wrd(e) << '\n'; return(-1);}catch(...) { Wy::cerr << "unknown unwind\n"; return(-1);};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -