📄 mpthread.cpp
字号:
#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(_T("The thread %ld is being destroyed although it is still running! The application may crash."), GetId());
}
m_critsect.Leave();
#endif // __WXDEBUG__
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) == false )
{
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,
_T("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(_T("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,
_T("a thread can't wait for itself") );
wxCHECK_MSG( !m_isDetached, (ExitCode)-1,
_T("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,
_T("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();
}
}
//else: can't wait for detached threads
}
return wxTHREAD_NO_ERROR;
}
wxThreadError wxThread::Kill()
{
wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
_T("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 )
{
wxLogError(_("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,
_T("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();
MPTerminateTask( m_internal->GetId() , (long) status) ;
if ( IsDetached() )
{
delete this;
}
else // joinable
{
// update the status of the joinable thread
wxCriticalSectionLocker lock(m_critsect);
m_internal->SetState(STATE_EXITED);
}
}
// also test whether we were paused
bool wxThread::TestDestroy()
{
wxASSERT_MSG( This() == this,
_T("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
// try 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()
{
if ( !wxMacMPThreadsInitVerify() )
{
return false ;
}
verify_noerr( MPAllocateTaskStorageIndex( &gs_tlsForWXThread ) ) ;
// main thread's This() is NULL
verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread , NULL ) ) ;
gs_idMainThread = wxThread::GetCurrentId() ;
gs_critsectWaitingForGui = new wxCriticalSection();
gs_critsectGui = new wxCriticalSection();
gs_critsectGui->Enter();
return true;
}
void wxThreadModule::OnExit()
{
if ( gs_critsectGui )
{
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()!") );
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 + -