📄 thread.cpp
字号:
m_shouldBeJoined = false; } }}void wxThreadInternal::Pause(){ // the state is set from the thread which pauses us first, this function // is called later so the state should have been already set wxCHECK_RET( m_state == STATE_PAUSED, wxT("thread must first be paused with wxThread::Pause().") ); // wait until the semaphore is Post()ed from Resume() m_semSuspend.Wait();}void wxThreadInternal::Resume(){ wxCHECK_RET( m_state == STATE_PAUSED, wxT("can't resume thread which is not suspended.") ); // the thread might be not actually paused yet - if there were no call to // TestDestroy() since the last call to Pause() for example if ( IsReallyPaused() ) { // wake up Pause() m_semSuspend.Post(); // reset the flag SetReallyPaused( false ); } SetState( STATE_RUNNING );}// static functions// ----------------wxThread *wxThread::This(){ wxThread* thr = (wxThread*) MPGetTaskStorageValue( gs_tlsForWXThread ) ; return thr;}bool wxThread::IsMain(){ return GetCurrentId() == gs_idMainThread || gs_idMainThread == kInvalidID ;}#ifdef Yield#undef Yield#endifvoid wxThread::Yield(){#if TARGET_API_MAC_OSX CFRunLoopRunInMode( kCFRunLoopDefaultMode , 0 , true ) ;#endif MPYield();}void wxThread::Sleep( unsigned long milliseconds ){ AbsoluteTime wakeup = AddDurationToAbsolute( milliseconds, UpTime() ); MPDelayUntil( &wakeup );}int wxThread::GetCPUCount(){ return MPProcessors();}unsigned long wxThread::GetCurrentId(){ return (unsigned long)MPCurrentTaskID();}bool wxThread::SetConcurrency( size_t level ){ // Cannot be set in MacOS. return false;}wxThread::wxThread( wxThreadKind kind ){ g_numberOfThreads++; m_internal = new wxThreadInternal(); m_isDetached = (kind == wxTHREAD_DETACHED);}wxThread::~wxThread(){ wxASSERT_MSG( g_numberOfThreads>0 , wxT("More threads deleted than created.") ) ; g_numberOfThreads--;#ifdef __WXDEBUG__ m_critsect.Enter(); // check that the thread either exited or couldn't be created if ( m_internal->GetState() != STATE_EXITED && m_internal->GetState() != STATE_NEW ) { wxLogDebug( wxT("The thread %ld is being destroyed although it is still running! The application may crash."), GetId() ); } m_critsect.Leave();#endif wxDELETE( m_internal ) ;}wxThreadError wxThread::Create( unsigned int stackSize ){ wxCriticalSectionLocker lock(m_critsect); if ( m_isDetached ) m_internal->Detach() ; if ( !m_internal->Create(this, stackSize) ) { m_internal->SetState( STATE_EXITED ); return wxTHREAD_NO_RESOURCE; } return wxTHREAD_NO_ERROR;}wxThreadError wxThread::Run(){ wxCriticalSectionLocker lock(m_critsect); wxCHECK_MSG( m_internal->GetId(), wxTHREAD_MISC_ERROR, wxT("must call wxThread::Create() first") ); return m_internal->Run();}// -----------------------------------------------------------------------------// pause/resume// -----------------------------------------------------------------------------wxThreadError wxThread::Pause(){ wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, _T("a thread can't pause itself") ); wxCriticalSectionLocker lock(m_critsect); if ( m_internal->GetState() != STATE_RUNNING ) { wxLogDebug( wxT("Can't pause thread which is not running.") ); return wxTHREAD_NOT_RUNNING; } // just set a flag, the thread will be really paused only during the next // call to TestDestroy() m_internal->SetState( STATE_PAUSED ); return wxTHREAD_NO_ERROR;}wxThreadError wxThread::Resume(){ wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, wxT("a thread can't resume itself") ); wxCriticalSectionLocker lock(m_critsect); wxThreadState state = m_internal->GetState(); switch ( state ) { case STATE_PAUSED: m_internal->Resume(); return wxTHREAD_NO_ERROR; case STATE_EXITED: return wxTHREAD_NO_ERROR; default: wxLogDebug( wxT("Attempt to resume a thread which is not paused.") ); return wxTHREAD_MISC_ERROR; }}// -----------------------------------------------------------------------------// exiting thread// -----------------------------------------------------------------------------wxThread::ExitCode wxThread::Wait(){ wxCHECK_MSG( This() != this, (ExitCode)-1, wxT("a thread can't wait for itself") ); wxCHECK_MSG( !m_isDetached, (ExitCode)-1, wxT("can't wait for detached thread") ); m_internal->Wait(); return m_internal->GetExitCode();}wxThreadError wxThread::Delete(ExitCode *rc){ wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, wxT("a thread can't delete itself") ); bool isDetached = m_isDetached; m_critsect.Enter(); wxThreadState state = m_internal->GetState(); // ask the thread to stop m_internal->SetCancelFlag(); m_critsect.Leave(); switch ( state ) { case STATE_NEW: // we need to wake up the thread so that PthreadStart() will // terminate - right now it's blocking on run semaphore in // PthreadStart() m_internal->SignalRun(); // fall through case STATE_EXITED: // nothing to do break; case STATE_PAUSED: // resume the thread first m_internal->Resume(); // fall through default: if ( !isDetached ) { // wait until the thread stops m_internal->Wait(); if ( rc ) { // return the exit code of the thread *rc = m_internal->GetExitCode(); } } } return wxTHREAD_NO_ERROR;}wxThreadError wxThread::Kill(){ wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR, wxT("a thread can't kill itself") ); switch ( m_internal->GetState() ) { case STATE_NEW: case STATE_EXITED: return wxTHREAD_NOT_RUNNING; case STATE_PAUSED: // resume the thread first Resume(); // fall through default: OSStatus err = MPTerminateTask( m_internal->GetId() , -1 ) ; if (err != noErr) { wxLogError( wxT("Failed to terminate a thread.") ); return wxTHREAD_MISC_ERROR; } if ( m_isDetached ) { delete this ; } else { // this should be retrieved by Wait actually m_internal->SetExitCode( (void*)-1 ); } return wxTHREAD_NO_ERROR; }}void wxThread::Exit( ExitCode status ){ wxASSERT_MSG( This() == this, wxT("wxThread::Exit() can only be called in the context of the same thread") ); // don't enter m_critsect before calling OnExit() because the user code // might deadlock if, for example, it signals a condition in OnExit() (a // common case) while the main thread calls any of functions entering // m_critsect on us (almost all of them do) OnExit(); MPTaskID threadid = m_internal->GetId(); if ( IsDetached() ) { delete this; } else // joinable { // update the status of the joinable thread wxCriticalSectionLocker lock( m_critsect ); m_internal->SetState( STATE_EXITED ); } MPTerminateTask( threadid, (long)status );}// also test whether we were pausedbool wxThread::TestDestroy(){ wxASSERT_MSG( This() == this, wxT("wxThread::TestDestroy() can only be called in the context of the same thread") ); m_critsect.Enter(); if ( m_internal->GetState() == STATE_PAUSED ) { m_internal->SetReallyPaused( true ); // leave the crit section or the other threads will stop too if they attempt // to call any of (seemingly harmless) IsXXX() functions while we sleep m_critsect.Leave(); m_internal->Pause(); } else { // thread wasn't requested to pause, nothing to do m_critsect.Leave(); } return m_internal->WasCancelled();}// -----------------------------------------------------------------------------// priority setting// -----------------------------------------------------------------------------void wxThread::SetPriority(unsigned int prio){ wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) && ((int)prio <= (int)WXTHREAD_MAX_PRIORITY), wxT("invalid thread priority") ); wxCriticalSectionLocker lock(m_critsect); switch ( m_internal->GetState() ) { case STATE_RUNNING: case STATE_PAUSED: case STATE_NEW: // thread not yet started, priority will be set when it is m_internal->SetPriority( prio ); break; case STATE_EXITED: default: wxFAIL_MSG( wxT("impossible to set thread priority in this state") ); }}unsigned int wxThread::GetPriority() const{ wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast return m_internal->GetPriority();}unsigned long wxThread::GetId() const{ wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast return (unsigned long)m_internal->GetId();}// -----------------------------------------------------------------------------// state tests// -----------------------------------------------------------------------------bool wxThread::IsRunning() const{ wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); return m_internal->GetState() == STATE_RUNNING;}bool wxThread::IsAlive() const{ wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); switch ( m_internal->GetState() ) { case STATE_RUNNING: case STATE_PAUSED: return true; default: return false; }}bool wxThread::IsPaused() const{ wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); return (m_internal->GetState() == STATE_PAUSED);}// ----------------------------------------------------------------------------// Automatic initialization for thread module// ----------------------------------------------------------------------------class wxThreadModule : public wxModule{public: virtual bool OnInit(); virtual void OnExit();private: DECLARE_DYNAMIC_CLASS(wxThreadModule)};IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)bool wxThreadModule::OnInit(){ bool hasThreadManager = #ifdef __LP64__ true ; // TODO VERIFY IN NEXT BUILD#else MPLibraryIsLoaded();#endif if ( !hasThreadManager ) { wxLogError( wxT("MP thread support is not available on this system" ) ) ; return false; } // main thread's This() is NULL verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread ) ) ; verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread, 0 ) ) ; gs_idMainThread = wxThread::GetCurrentId(); gs_critsectWaitingForGui = new wxCriticalSection(); gs_critsectGui = new wxCriticalSection(); gs_critsectGui->Enter(); return true;}void wxThreadModule::OnExit(){ if ( gs_critsectGui ) { if ( !wxGuiOwnedByMainThread() ) { gs_critsectGui->Enter(); gs_bGuiOwnedByMainThread = true; } gs_critsectGui->Leave(); delete gs_critsectGui; gs_critsectGui = NULL; } delete gs_critsectWaitingForGui; gs_critsectWaitingForGui = NULL;}// ----------------------------------------------------------------------------// GUI Serialization copied from MSW implementation// ----------------------------------------------------------------------------void WXDLLIMPEXP_BASE wxMutexGuiEnter(){ // this would dead lock everything... wxASSERT_MSG( !wxThread::IsMain(), wxT("main thread doesn't want to block in wxMutexGuiEnter()!") ); // the order in which we enter the critical sections here is crucial!! // set the flag telling to the main thread that we want to do some GUI { wxCriticalSectionLocker enter(*gs_critsectWaitingForGui); gs_nWaitingForGui++; } wxWakeUpMainThread(); // now we may block here because the main thread will soon let us in // (during the next iteration of OnIdle()) gs_critsectGui->Enter();}void WXDLLIMPEXP_BASE wxMutexGuiLeave(){ wxCriticalSectionLocker enter(*gs_critsectWaitingForGui); if ( wxThread::IsMain() ) { gs_bGuiOwnedByMainThread = false; } else { // decrement the number of threads waiting for GUI access now wxASSERT_MSG( gs_nWaitingForGui > 0, wxT("calling wxMutexGuiLeave() without entering it first?") ); gs_nWaitingForGui--; wxWakeUpMainThread(); } gs_critsectGui->Leave();}void WXDLLIMPEXP_BASE wxMutexGuiLeaveOrEnter(){ wxASSERT_MSG( wxThread::IsMain(), wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") ); if ( !gs_critsectWaitingForGui ) return; wxCriticalSectionLocker enter(*gs_critsectWaitingForGui); if ( gs_nWaitingForGui == 0 ) { // no threads are waiting for GUI - so we may acquire the lock without // any danger (but only if we don't already have it) if ( !wxGuiOwnedByMainThread() ) { gs_critsectGui->Enter(); gs_bGuiOwnedByMainThread = true; } //else: already have it, nothing to do } else { // some threads are waiting, release the GUI lock if we have it if ( wxGuiOwnedByMainThread() ) wxMutexGuiLeave(); //else: some other worker thread is doing GUI }}bool WXDLLIMPEXP_BASE wxGuiOwnedByMainThread(){ return gs_bGuiOwnedByMainThread;}// wake up the main threadvoid WXDLLEXPORT wxWakeUpMainThread(){ wxMacWakeUp();}// ----------------------------------------------------------------------------// include common implementation code// ----------------------------------------------------------------------------#include "wx/thrimpl.cpp"#endif // wxUSE_THREADS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -