threadpsx.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,725 行 · 第 1/4 页
CPP
1,725 行
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:
wxLogTrace(TRACE_THREADS, _T("Thread %ld suspended, resuming."),
GetId());
m_internal->Resume();
return wxTHREAD_NO_ERROR;
case STATE_EXITED:
wxLogTrace(TRACE_THREADS, _T("Thread %ld exited, won't resume."),
GetId());
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:
#ifdef HAVE_PTHREAD_CANCEL
if ( pthread_cancel(m_internal->GetId()) != 0 )
#endif
{
wxLogError(_("Failed to terminate a thread."));
return wxTHREAD_MISC_ERROR;
}
if ( m_isDetached )
{
// if we use cleanup function, this will be done from
// wxPthreadCleanup()
#ifndef wxHAVE_PTHREAD_CLEANUP
ScheduleThreadForDeletion();
// don't call OnExit() here, it can only be called in the
// threads context and we're in the context of another thread
DeleteThread(this);
#endif // wxHAVE_PTHREAD_CLEANUP
}
else
{
m_internal->SetExitCode(EXITCODE_CANCELLED);
}
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") );
if ( m_isDetached )
{
// from the moment we call OnExit(), the main program may terminate at
// any moment, so mark this thread as being already in process of being
// deleted or wxThreadModule::OnExit() will try to delete it again
ScheduleThreadForDeletion();
}
// 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();
// delete C++ thread object if this is a detached thread - user is
// responsible for doing this for joinable ones
if ( m_isDetached )
{
// FIXME I'm feeling bad about it - what if another thread function is
// called (in another thread context) now? It will try to access
// half destroyed object which will probably result in something
// very bad - but we can't protect this by a crit section unless
// we make it a global object, but this would mean that we can
// only call one thread function at a time :-(
DeleteThread(this);
pthread_setspecific(gs_keySelf, 0);
}
else
{
m_critsect.Enter();
m_internal->SetState(STATE_EXITED);
m_critsect.Leave();
}
// terminate the thread (pthread_exit() never returns)
pthread_exit(status);
wxFAIL_MSG(_T("pthread_exit() failed"));
}
// 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();
}
wxThread::~wxThread()
{
#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__
delete m_internal;
// remove this thread from the global array
gs_allThreads.Remove(this);
}
// -----------------------------------------------------------------------------
// 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);
}
//--------------------------------------------------------------------
// wxThreadModule
//--------------------------------------------------------------------
class wxThreadModule : public wxModule
{
public:
virtual bool OnInit();
virtual void OnExit();
private:
DECLARE_DYNAMIC_CLASS(wxThreadModule)
};
IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
bool wxThreadModule::OnInit()
{
int rc = pthread_key_create(&gs_keySelf, NULL /* dtor function */);
if ( rc != 0 )
{
wxLogSysError(rc, _("Thread module initialization failed: failed to create thread key"));
return FALSE;
}
gs_tidMain = pthread_self();
gs_mutexGui = new wxMutex();
gs_mutexGui->Lock();
gs_mutexDeleteThread = new wxMutex();
gs_condAllDeleted = new wxCondition( *gs_mutexDeleteThread );
return TRUE;
}
void wxThreadModule::OnExit()
{
wxASSERT_MSG( wxThread::IsMain(), wxT("only main thread can be here") );
// are there any threads left which are being deleted right now?
size_t nThreadsBeingDeleted;
{
wxMutexLocker lock( *gs_mutexDeleteThread );
nThreadsBeingDeleted = gs_nThreadsBeingDeleted;
if ( nThreadsBeingDeleted > 0 )
{
wxLogTrace(TRACE_THREADS,
_T("Waiting for %lu threads to disappear"),
(unsigned long)nThreadsBeingDeleted);
// have to wait until all of them disappear
gs_condAllDeleted->Wait();
}
}
// terminate any threads left
size_t count = gs_allThreads.GetCount();
if ( count != 0u )
{
wxLogDebug(wxT("%lu threads were not terminated by the application."),
(unsigned long)count);
}
for ( size_t n = 0u; n < count; n++ )
{
// Delete calls the destructor which removes the current entry. We
// should only delete the first one each time.
gs_allThreads[0]->Delete();
}
// destroy GUI mutex
gs_mutexGui->Unlock();
delete gs_mutexGui;
// and free TLD slot
(void)pthread_key_delete(gs_keySelf);
delete gs_condAllDeleted;
delete gs_mutexDeleteThread;
}
// ----------------------------------------------------------------------------
// global functions
// ----------------------------------------------------------------------------
static void ScheduleThreadForDeletion()
{
wxMutexLocker lock( *gs_mutexDeleteThread );
gs_nThreadsBeingDeleted++;
wxLogTrace(TRACE_THREADS, _T("%lu thread%s waiting to be deleted"),
(unsigned long)gs_nThreadsBeingDeleted,
gs_nThreadsBeingDeleted == 1 ? "" : "s");
}
static void DeleteThread(wxThread *This)
{
// gs_mutexDeleteThread should be unlocked before signalling the condition
// or wxThreadModule::OnExit() would deadlock
wxMutexLocker locker( *gs_mutexDeleteThread );
wxLogTrace(TRACE_THREADS, _T("Thread %ld auto deletes."), This->GetId());
delete This;
wxCHECK_RET( gs_nThreadsBeingDeleted > 0,
_T("no threads scheduled for deletion, yet we delete one?") );
wxLogTrace(TRACE_THREADS, _T("%lu scheduled for deletion threads left."),
(unsigned long)gs_nThreadsBeingDeleted - 1);
if ( !--gs_nThreadsBeingDeleted )
{
// no more threads left, signal it
gs_condAllDeleted->Signal();
}
}
void wxMutexGuiEnter()
{
gs_mutexGui->Lock();
}
void wxMutexGuiLeave()
{
gs_mutexGui->Unlock();
}
// ----------------------------------------------------------------------------
// include common implementation code
// ----------------------------------------------------------------------------
#include "wx/thrimpl.cpp"
#endif // wxUSE_THREADS
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?