thread.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,353 行 · 第 1/3 页
CPP
1,353 行
HANDLE hProcess = ::GetCurrentProcess();
DWORD_PTR dwProcMask, dwSysMask;
if ( ::GetProcessAffinityMask(hProcess, &dwProcMask, &dwSysMask) == 0 )
{
wxLogLastError(_T("GetProcessAffinityMask"));
return false;
}
// how many CPUs have we got?
if ( dwSysMask == 1 )
{
// don't bother with all this complicated stuff - on a single
// processor system it doesn't make much sense anyhow
return level == 1;
}
// calculate the process mask: it's a bit vector with one bit per
// processor; we want to schedule the process to run on first level
// CPUs
DWORD bit = 1;
while ( bit )
{
if ( dwSysMask & bit )
{
// ok, we can set this bit
dwProcMask |= bit;
// another process added
if ( !--level )
{
// and that's enough
break;
}
}
// next bit
bit <<= 1;
}
// could we set all bits?
if ( level != 0 )
{
wxLogDebug(_T("bad level %u in wxThread::SetConcurrency()"), level);
return false;
}
// set it: we can't link to SetProcessAffinityMask() because it doesn't
// exist in Win9x, use RT binding instead
typedef BOOL (*SETPROCESSAFFINITYMASK)(HANDLE, DWORD);
// can use static var because we're always in the main thread here
static SETPROCESSAFFINITYMASK pfnSetProcessAffinityMask = NULL;
if ( !pfnSetProcessAffinityMask )
{
HMODULE hModKernel = ::LoadLibrary(_T("kernel32"));
if ( hModKernel )
{
pfnSetProcessAffinityMask = (SETPROCESSAFFINITYMASK)
::GetProcAddress(hModKernel, "SetProcessAffinityMask");
}
// we've discovered a MT version of Win9x!
wxASSERT_MSG( pfnSetProcessAffinityMask,
_T("this system has several CPUs but no SetProcessAffinityMask function?") );
}
if ( !pfnSetProcessAffinityMask )
{
// msg given above - do it only once
return false;
}
if ( pfnSetProcessAffinityMask(hProcess, dwProcMask) == 0 )
{
wxLogLastError(_T("SetProcessAffinityMask"));
return false;
}
return true;
#endif // __WXWINCE__/!__WXWINCE__
}
// ctor and dtor
// -------------
wxThread::wxThread(wxThreadKind kind)
{
m_internal = new wxThreadInternal(this);
m_isDetached = kind == wxTHREAD_DETACHED;
}
wxThread::~wxThread()
{
delete m_internal;
}
// create/start thread
// -------------------
wxThreadError wxThread::Create(unsigned int stackSize)
{
wxCriticalSectionLocker lock(m_critsect);
if ( !m_internal->Create(this, stackSize) )
return wxTHREAD_NO_RESOURCE;
return wxTHREAD_NO_ERROR;
}
wxThreadError wxThread::Run()
{
wxCriticalSectionLocker lock(m_critsect);
if ( m_internal->GetState() != STATE_NEW )
{
// actually, it may be almost any state at all, not only STATE_RUNNING
return wxTHREAD_RUNNING;
}
// the thread has just been created and is still suspended - let it run
return Resume();
}
// suspend/resume thread
// ---------------------
wxThreadError wxThread::Pause()
{
wxCriticalSectionLocker lock(m_critsect);
return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
}
wxThreadError wxThread::Resume()
{
wxCriticalSectionLocker lock(m_critsect);
return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
}
// stopping thread
// ---------------
wxThread::ExitCode wxThread::Wait()
{
// although under Windows we can wait for any thread, it's an error to
// wait for a detached one in wxWin API
wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
_T("wxThread::Wait(): can't wait for detached thread") );
ExitCode rc = (ExitCode)-1;
(void)m_internal->WaitForTerminate(m_critsect, &rc);
return rc;
}
wxThreadError wxThread::Delete(ExitCode *pRc)
{
return m_internal->WaitForTerminate(m_critsect, pRc, this);
}
wxThreadError wxThread::Kill()
{
if ( !IsRunning() )
return wxTHREAD_NOT_RUNNING;
wxThreadError rc = m_internal->Kill();
if ( IsDetached() )
{
delete this;
}
else // joinable
{
// update the status of the joinable thread
wxCriticalSectionLocker lock(m_critsect);
m_internal->SetState(STATE_EXITED);
}
return rc;
}
void wxThread::Exit(ExitCode status)
{
m_internal->Free();
if ( IsDetached() )
{
delete this;
}
else // joinable
{
// update the status of the joinable thread
wxCriticalSectionLocker lock(m_critsect);
m_internal->SetState(STATE_EXITED);
}
#ifdef wxUSE_BEGIN_THREAD
_endthreadex((unsigned)status);
#else // !VC++
::ExitThread((DWORD)status);
#endif // VC++/!VC++
wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
}
// priority setting
// ----------------
void wxThread::SetPriority(unsigned int prio)
{
wxCriticalSectionLocker lock(m_critsect);
m_internal->SetPriority(prio);
}
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();
}
bool wxThread::IsRunning() const
{
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
return m_internal->GetState() == STATE_RUNNING;
}
bool wxThread::IsAlive() const
{
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
return (m_internal->GetState() == STATE_RUNNING) ||
(m_internal->GetState() == STATE_PAUSED);
}
bool wxThread::IsPaused() const
{
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
return m_internal->GetState() == STATE_PAUSED;
}
bool wxThread::TestDestroy()
{
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
return m_internal->GetState() == STATE_CANCELED;
}
// ----------------------------------------------------------------------------
// 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()
{
// allocate TLS index for storing the pointer to the current thread
gs_tlsThisThread = ::TlsAlloc();
if ( gs_tlsThisThread == 0xFFFFFFFF )
{
// in normal circumstances it will only happen if all other
// TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
// words, this should never happen
wxLogSysError(_("Thread module initialization failed: impossible to allocate index in thread local storage"));
return false;
}
// main thread doesn't have associated wxThread object, so store 0 in the
// TLS instead
if ( !::TlsSetValue(gs_tlsThisThread, (LPVOID)0) )
{
::TlsFree(gs_tlsThisThread);
gs_tlsThisThread = 0xFFFFFFFF;
wxLogSysError(_("Thread module initialization failed: can not store value in thread local storage"));
return false;
}
gs_critsectWaitingForGui = new wxCriticalSection();
gs_critsectGui = new wxCriticalSection();
gs_critsectGui->Enter();
gs_critsectThreadDelete = new wxCriticalSection;
// no error return for GetCurrentThreadId()
gs_idMainThread = ::GetCurrentThreadId();
return true;
}
void wxThreadModule::OnExit()
{
if ( !::TlsFree(gs_tlsThisThread) )
{
wxLogLastError(wxT("TlsFree failed."));
}
delete gs_critsectThreadDelete;
gs_critsectThreadDelete = NULL;
if ( gs_critsectGui )
{
gs_critsectGui->Leave();
delete gs_critsectGui;
gs_critsectGui = NULL;
}
delete gs_critsectWaitingForGui;
gs_critsectWaitingForGui = NULL;
}
// ----------------------------------------------------------------------------
// under Windows, these functions are implemented using a critical section and
// not a mutex, so the names are a bit confusing
// ----------------------------------------------------------------------------
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 if it's in ::GetMessage()
void WXDLLIMPEXP_BASE wxWakeUpMainThread()
{
// sending any message would do - hopefully WM_NULL is harmless enough
if ( !::PostThreadMessage(gs_idMainThread, WM_NULL, 0, 0) )
{
// should never happen
wxLogLastError(wxT("PostThreadMessage(WM_NULL)"));
}
}
bool WXDLLIMPEXP_BASE wxIsWaitingForThread()
{
return gs_waitingForThread;
}
// ----------------------------------------------------------------------------
// include common implementation code
// ----------------------------------------------------------------------------
#include "wx/thrimpl.cpp"
#endif // wxUSE_THREADS
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?