threadpsx.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,725 行 · 第 1/4 页
CPP
1,725 行
return wxTHREAD_NO_ERROR;
}
void wxThreadInternal::Wait()
{
wxCHECK_RET( !m_isDetached, _T("can't wait for a detached thread") );
// if the thread we're waiting for is waiting for the GUI mutex, we will
// deadlock so make sure we release it temporarily
if ( wxThread::IsMain() )
wxMutexGuiLeave();
wxLogTrace(TRACE_THREADS,
_T("Starting to wait for thread %ld to exit."),
THR_ID(this));
// to avoid memory leaks we should call pthread_join(), but it must only be
// done once so use a critical section to serialize the code below
{
wxCriticalSectionLocker lock(m_csJoinFlag);
if ( m_shouldBeJoined )
{
// FIXME shouldn't we set cancellation type to DISABLED here? If
// we're cancelled inside pthread_join(), things will almost
// certainly break - but if we disable the cancellation, we
// might deadlock
if ( pthread_join(GetId(), &m_exitcode) != 0 )
{
// this is a serious problem, so use wxLogError and not
// wxLogDebug: it is possible to bring the system to its knees
// by creating too many threads and not joining them quite
// easily
wxLogError(_("Failed to join a thread, potential memory leak detected - please restart the program"));
}
m_shouldBeJoined = FALSE;
}
}
// reacquire GUI mutex
if ( wxThread::IsMain() )
wxMutexGuiEnter();
}
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().") );
wxLogTrace(TRACE_THREADS,
_T("Thread %ld goes to sleep."), THR_ID(this));
// 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() )
{
wxLogTrace(TRACE_THREADS,
_T("Waking up thread %ld"), THR_ID(this));
// wake up Pause()
m_semSuspend.Post();
// reset the flag
SetReallyPaused(FALSE);
}
else
{
wxLogTrace(TRACE_THREADS,
_T("Thread %ld is not yet really paused"), THR_ID(this));
}
SetState(STATE_RUNNING);
}
// -----------------------------------------------------------------------------
// wxThread static functions
// -----------------------------------------------------------------------------
wxThread *wxThread::This()
{
return (wxThread *)pthread_getspecific(gs_keySelf);
}
bool wxThread::IsMain()
{
return (bool)pthread_equal(pthread_self(), gs_tidMain) || gs_tidMain == (pthread_t)-1;
}
void wxThread::Yield()
{
#ifdef HAVE_SCHED_YIELD
sched_yield();
#endif
}
void wxThread::Sleep(unsigned long milliseconds)
{
wxMilliSleep(milliseconds);
}
int wxThread::GetCPUCount()
{
#if defined(__LINUX__) && wxUSE_FFILE
// read from proc (can't use wxTextFile here because it's a special file:
// it has 0 size but still can be read from)
wxLogNull nolog;
wxFFile file(_T("/proc/cpuinfo"));
if ( file.IsOpened() )
{
// slurp the whole file
wxString s;
if ( file.ReadAll(&s) )
{
// (ab)use Replace() to find the number of "processor: num" strings
size_t count = s.Replace(_T("processor\t:"), _T(""));
if ( count > 0 )
{
return count;
}
wxLogDebug(_T("failed to parse /proc/cpuinfo"));
}
else
{
wxLogDebug(_T("failed to read /proc/cpuinfo"));
}
}
#elif defined(_SC_NPROCESSORS_ONLN)
// this works for Solaris
int rc = sysconf(_SC_NPROCESSORS_ONLN);
if ( rc != -1 )
{
return rc;
}
#endif // different ways to get number of CPUs
// unknown
return -1;
}
// VMS is a 64 bit system and threads have 64 bit pointers.
// FIXME: also needed for other systems????
#ifdef __VMS
unsigned long long wxThread::GetCurrentId()
{
return (unsigned long long)pthread_self();
}
#else // !__VMS
unsigned long wxThread::GetCurrentId()
{
return (unsigned long)pthread_self();
}
#endif // __VMS/!__VMS
bool wxThread::SetConcurrency(size_t level)
{
#ifdef HAVE_THR_SETCONCURRENCY
int rc = thr_setconcurrency(level);
if ( rc != 0 )
{
wxLogSysError(rc, _T("thr_setconcurrency() failed"));
}
return rc == 0;
#else // !HAVE_THR_SETCONCURRENCY
// ok only for the default value
return level == 0;
#endif // HAVE_THR_SETCONCURRENCY/!HAVE_THR_SETCONCURRENCY
}
// -----------------------------------------------------------------------------
// creating thread
// -----------------------------------------------------------------------------
wxThread::wxThread(wxThreadKind kind)
{
// add this thread to the global list of all threads
gs_allThreads.Add(this);
m_internal = new wxThreadInternal();
m_isDetached = kind == wxTHREAD_DETACHED;
}
wxThreadError wxThread::Create(unsigned int WXUNUSED(stackSize))
{
if ( m_internal->GetState() != STATE_NEW )
{
// don't recreate thread
return wxTHREAD_RUNNING;
}
// set up the thread attribute: right now, we only set thread priority
pthread_attr_t attr;
pthread_attr_init(&attr);
#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
int policy;
if ( pthread_attr_getschedpolicy(&attr, &policy) != 0 )
{
wxLogError(_("Cannot retrieve thread scheduling policy."));
}
#ifdef __VMS__
/* the pthread.h contains too many spaces. This is a work-around */
# undef sched_get_priority_max
#undef sched_get_priority_min
#define sched_get_priority_max(_pol_) \
(_pol_ == SCHED_OTHER ? PRI_FG_MAX_NP : PRI_FIFO_MAX)
#define sched_get_priority_min(_pol_) \
(_pol_ == SCHED_OTHER ? PRI_FG_MIN_NP : PRI_FIFO_MIN)
#endif
int max_prio = sched_get_priority_max(policy),
min_prio = sched_get_priority_min(policy),
prio = m_internal->GetPriority();
if ( min_prio == -1 || max_prio == -1 )
{
wxLogError(_("Cannot get priority range for scheduling policy %d."),
policy);
}
else if ( max_prio == min_prio )
{
if ( prio != WXTHREAD_DEFAULT_PRIORITY )
{
// notify the programmer that this doesn't work here
wxLogWarning(_("Thread priority setting is ignored."));
}
//else: we have default priority, so don't complain
// anyhow, don't do anything because priority is just ignored
}
else
{
struct sched_param sp;
if ( pthread_attr_getschedparam(&attr, &sp) != 0 )
{
wxFAIL_MSG(_T("pthread_attr_getschedparam() failed"));
}
sp.sched_priority = min_prio + (prio*(max_prio - min_prio))/100;
if ( pthread_attr_setschedparam(&attr, &sp) != 0 )
{
wxFAIL_MSG(_T("pthread_attr_setschedparam(priority) failed"));
}
}
#endif // HAVE_THREAD_PRIORITY_FUNCTIONS
#ifdef HAVE_PTHREAD_ATTR_SETSCOPE
// this will make the threads created by this process really concurrent
if ( pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0 )
{
wxFAIL_MSG(_T("pthread_attr_setscope(PTHREAD_SCOPE_SYSTEM) failed"));
}
#endif // HAVE_PTHREAD_ATTR_SETSCOPE
// VZ: assume that this one is always available (it's rather fundamental),
// if this function is ever missing we should try to use
// pthread_detach() instead (after thread creation)
if ( m_isDetached )
{
if ( pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0 )
{
wxFAIL_MSG(_T("pthread_attr_setdetachstate(DETACHED) failed"));
}
// never try to join detached threads
m_internal->Detach();
}
//else: threads are created joinable by default, it's ok
// create the new OS thread object
int rc = pthread_create
(
m_internal->GetIdPtr(),
&attr,
wxPthreadStart,
(void *)this
);
if ( pthread_attr_destroy(&attr) != 0 )
{
wxFAIL_MSG(_T("pthread_attr_destroy() failed"));
}
if ( rc != 0 )
{
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();
}
// -----------------------------------------------------------------------------
// misc accessors
// -----------------------------------------------------------------------------
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_NEW:
// thread not yet started, priority will be set when it is
m_internal->SetPriority(prio);
break;
case STATE_RUNNING:
case STATE_PAUSED:
#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
#if defined(__LINUX__)
// On Linux, pthread_setschedparam with SCHED_OTHER does not allow
// a priority other than 0. Instead, we use the BSD setpriority
// which alllows us to set a 'nice' value between 20 to -20. Only
// super user can set a value less than zero (more negative yields
// higher priority). setpriority set the static priority of a process,
// but this is OK since Linux is configured as a thread per process.
{
float fPrio;
float pSpan;
int iPrio;
// Map Wx priorites (WXTHREAD_MIN_PRIORITY -
// WXTHREAD_MAX_PRIORITY) into BSD priorities (20 - -20).
// Do calculation of values instead of hard coding them
// to make maintenance easier.
pSpan = ((float)(WXTHREAD_MAX_PRIORITY - WXTHREAD_MIN_PRIORITY)) / 2.0;
// prio starts as ................... // value => (0) >= p <= (n)
fPrio = ((float)prio) - pSpan; // value => (-n) >= p <= (+n)
fPrio = 0.0 - fPrio; // value => (+n) <= p >= (-n)
fPrio = fPrio * (20. / pSpan) + .5; // value => (20) <= p >= (-20)
iPrio = (int)fPrio;
// Clamp prio from 20 - -20;
iPrio = (iPrio > 20) ? 20 : iPrio;
iPrio = (iPrio < -20) ? -20 : iPrio;
if (setpriority(PRIO_PROCESS, 0, iPrio) == -1)
{
wxLogError(_("Failed to set thread priority %d."), prio);
}
}
#else // __LINUX__
{
struct sched_param sparam;
sparam.sched_priority = prio;
if ( pthread_setschedparam(m_internal->GetId(),
SCHED_OTHER, &sparam) != 0 )
{
wxLogError(_("Failed to set thread priority %d."), prio);
}
}
#endif // __LINUX__
#endif // HAVE_THREAD_PRIORITY_FUNCTIONS
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);
return m_internal->GetPriority();
}
wxThreadIdType wxThread::GetId() const
{
return (wxThreadIdType) m_internal->GetId();
}
// -----------------------------------------------------------------------------
// 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."));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?