📄 thread.cpp
字号:
// 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 paused
bool 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 = MPLibraryIsLoaded();
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 thread
void WXDLLEXPORT wxWakeUpMainThread()
{
wxMacWakeUp();
}
// ----------------------------------------------------------------------------
// include common implementation code
// ----------------------------------------------------------------------------
#include "wx/thrimpl.cpp"
#endif // wxUSE_THREADS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -