thread.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,353 行 · 第 1/3 页
CPP
1,353 行
/////////////////////////////////////////////////////////////////////////////
// Name: src/msw/thread.cpp
// Purpose: wxThread Implementation
// Author: Original from Wolfram Gloger/Guilhem Lavaux
// Modified by: Vadim Zeitlin to make it work :-)
// Created: 04/22/98
// RCS-ID: $Id: thread.cpp,v 1.95 2005/07/01 13:38:58 ABX Exp $
// Copyright: (c) Wolfram Gloger (1996, 1997), Guilhem Lavaux (1998);
// Vadim Zeitlin (1999-2002)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "thread.h"
#endif
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#if defined(__BORLANDC__)
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/intl.h"
#include "wx/app.h"
#endif
#if wxUSE_THREADS
#include "wx/apptrait.h"
#include "wx/msw/private.h"
#include "wx/msw/missing.h"
#include "wx/module.h"
#include "wx/thread.h"
// must have this symbol defined to get _beginthread/_endthread declarations
#ifndef _MT
#define _MT
#endif
#if defined(__BORLANDC__)
#if !defined(__MT__)
// I can't set -tWM in the IDE (anyone?) so have to do this
#define __MT__
#endif
#if !defined(__MFC_COMPAT__)
// Needed to know about _beginthreadex etc..
#define __MFC_COMPAT__
#endif
#endif // BC++
// define wxUSE_BEGIN_THREAD if the compiler has _beginthreadex() function
// which should be used instead of Win32 ::CreateThread() if possible
#if defined(__VISUALC__) || \
(defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) || \
(defined(__GNUG__) && defined(__MSVCRT__)) || \
defined(__WATCOMC__) || defined(__MWERKS__)
#ifndef __WXWINCE__
#undef wxUSE_BEGIN_THREAD
#define wxUSE_BEGIN_THREAD
#endif
#endif
#ifdef wxUSE_BEGIN_THREAD
// this is where _beginthreadex() is declared
#include <process.h>
// the return type of the thread function entry point
typedef unsigned THREAD_RETVAL;
// the calling convention of the thread function entry point
#define THREAD_CALLCONV __stdcall
#else
// the settings for CreateThread()
typedef DWORD THREAD_RETVAL;
#define THREAD_CALLCONV WINAPI
#endif
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// the possible states of the thread ("=>" shows all possible transitions from
// this state)
enum wxThreadState
{
STATE_NEW, // didn't start execution yet (=> RUNNING)
STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
STATE_EXITED // thread is terminating
};
// ----------------------------------------------------------------------------
// this module globals
// ----------------------------------------------------------------------------
// TLS index of the slot where we store the pointer to the current thread
static DWORD gs_tlsThisThread = 0xFFFFFFFF;
// id of the main thread - the one which can call GUI functions without first
// calling wxMutexGuiEnter()
static DWORD gs_idMainThread = 0;
// if it's false, some secondary thread is holding the GUI lock
static bool gs_bGuiOwnedByMainThread = true;
// critical section which controls access to all GUI functions: any secondary
// thread (i.e. except the main one) must enter this crit section before doing
// any GUI calls
static wxCriticalSection *gs_critsectGui = NULL;
// critical section which protects gs_nWaitingForGui variable
static wxCriticalSection *gs_critsectWaitingForGui = NULL;
// critical section which serializes WinThreadStart() and WaitForTerminate()
// (this is a potential bottleneck, we use a single crit sect for all threads
// in the system, but normally time spent inside it should be quite short)
static wxCriticalSection *gs_critsectThreadDelete = NULL;
// number of threads waiting for GUI in wxMutexGuiEnter()
static size_t gs_nWaitingForGui = 0;
// are we waiting for a thread termination?
static bool gs_waitingForThread = false;
// ============================================================================
// Windows implementation of thread and related classes
// ============================================================================
// ----------------------------------------------------------------------------
// wxCriticalSection
// ----------------------------------------------------------------------------
wxCriticalSection::wxCriticalSection()
{
wxCOMPILE_TIME_ASSERT( sizeof(CRITICAL_SECTION) <= sizeof(wxCritSectBuffer),
wxCriticalSectionBufferTooSmall );
::InitializeCriticalSection((CRITICAL_SECTION *)m_buffer);
}
wxCriticalSection::~wxCriticalSection()
{
::DeleteCriticalSection((CRITICAL_SECTION *)m_buffer);
}
void wxCriticalSection::Enter()
{
::EnterCriticalSection((CRITICAL_SECTION *)m_buffer);
}
void wxCriticalSection::Leave()
{
::LeaveCriticalSection((CRITICAL_SECTION *)m_buffer);
}
// ----------------------------------------------------------------------------
// wxMutex
// ----------------------------------------------------------------------------
class wxMutexInternal
{
public:
wxMutexInternal(wxMutexType mutexType);
~wxMutexInternal();
bool IsOk() const { return m_mutex != NULL; }
wxMutexError Lock() { return LockTimeout(INFINITE); }
wxMutexError TryLock() { return LockTimeout(0); }
wxMutexError Unlock();
private:
wxMutexError LockTimeout(DWORD milliseconds);
HANDLE m_mutex;
DECLARE_NO_COPY_CLASS(wxMutexInternal)
};
// all mutexes are recursive under Win32 so we don't use mutexType
wxMutexInternal::wxMutexInternal(wxMutexType WXUNUSED(mutexType))
{
// create a nameless (hence intra process and always private) mutex
m_mutex = ::CreateMutex
(
NULL, // default secutiry attributes
false, // not initially locked
NULL // no name
);
if ( !m_mutex )
{
wxLogLastError(_T("CreateMutex()"));
}
}
wxMutexInternal::~wxMutexInternal()
{
if ( m_mutex )
{
if ( !::CloseHandle(m_mutex) )
{
wxLogLastError(_T("CloseHandle(mutex)"));
}
}
}
wxMutexError wxMutexInternal::LockTimeout(DWORD milliseconds)
{
DWORD rc = ::WaitForSingleObject(m_mutex, milliseconds);
if ( rc == WAIT_ABANDONED )
{
// the previous caller died without releasing the mutex, but now we can
// really lock it
wxLogDebug(_T("WaitForSingleObject() returned WAIT_ABANDONED"));
// use 0 timeout, normally we should always get it
rc = ::WaitForSingleObject(m_mutex, 0);
}
switch ( rc )
{
case WAIT_OBJECT_0:
// ok
break;
case WAIT_TIMEOUT:
return wxMUTEX_BUSY;
case WAIT_ABANDONED: // checked for above
default:
wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
// fall through
case WAIT_FAILED:
wxLogLastError(_T("WaitForSingleObject(mutex)"));
return wxMUTEX_MISC_ERROR;
}
return wxMUTEX_NO_ERROR;
}
wxMutexError wxMutexInternal::Unlock()
{
if ( !::ReleaseMutex(m_mutex) )
{
wxLogLastError(_T("ReleaseMutex()"));
return wxMUTEX_MISC_ERROR;
}
return wxMUTEX_NO_ERROR;
}
// --------------------------------------------------------------------------
// wxSemaphore
// --------------------------------------------------------------------------
// a trivial wrapper around Win32 semaphore
class wxSemaphoreInternal
{
public:
wxSemaphoreInternal(int initialcount, int maxcount);
~wxSemaphoreInternal();
bool IsOk() const { return m_semaphore != NULL; }
wxSemaError Wait() { return WaitTimeout(INFINITE); }
wxSemaError TryWait()
{
wxSemaError rc = WaitTimeout(0);
if ( rc == wxSEMA_TIMEOUT )
rc = wxSEMA_BUSY;
return rc;
}
wxSemaError WaitTimeout(unsigned long milliseconds);
wxSemaError Post();
private:
HANDLE m_semaphore;
DECLARE_NO_COPY_CLASS(wxSemaphoreInternal)
};
wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
{
#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 300)
if ( maxcount == 0 )
{
// make it practically infinite
maxcount = INT_MAX;
}
m_semaphore = ::CreateSemaphore
(
NULL, // default security attributes
initialcount,
maxcount,
NULL // no name
);
#endif
if ( !m_semaphore )
{
wxLogLastError(_T("CreateSemaphore()"));
}
}
wxSemaphoreInternal::~wxSemaphoreInternal()
{
if ( m_semaphore )
{
if ( !::CloseHandle(m_semaphore) )
{
wxLogLastError(_T("CloseHandle(semaphore)"));
}
}
}
wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
{
DWORD rc = ::WaitForSingleObject( m_semaphore, milliseconds );
switch ( rc )
{
case WAIT_OBJECT_0:
return wxSEMA_NO_ERROR;
case WAIT_TIMEOUT:
return wxSEMA_TIMEOUT;
default:
wxLogLastError(_T("WaitForSingleObject(semaphore)"));
}
return wxSEMA_MISC_ERROR;
}
wxSemaError wxSemaphoreInternal::Post()
{
#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 300)
if ( !::ReleaseSemaphore(m_semaphore, 1, NULL /* ptr to previous count */) )
#endif
{
wxLogLastError(_T("ReleaseSemaphore"));
return wxSEMA_MISC_ERROR;
}
return wxSEMA_NO_ERROR;
}
// ----------------------------------------------------------------------------
// wxThread implementation
// ----------------------------------------------------------------------------
// wxThreadInternal class
// ----------------------
class wxThreadInternal
{
public:
wxThreadInternal(wxThread *thread)
{
m_thread = thread;
m_hThread = 0;
m_state = STATE_NEW;
m_priority = WXTHREAD_DEFAULT_PRIORITY;
m_nRef = 1;
}
~wxThreadInternal()
{
Free();
}
void Free()
{
if ( m_hThread )
{
if ( !::CloseHandle(m_hThread) )
{
wxLogLastError(wxT("CloseHandle(thread)"));
}
m_hThread = 0;
}
}
// create a new (suspended) thread (for the given thread object)
bool Create(wxThread *thread, unsigned int stackSize);
// wait for the thread to terminate, either by itself, or by asking it
// (politely, this is not Kill()!) to do it
wxThreadError WaitForTerminate(wxCriticalSection& cs,
wxThread::ExitCode *pRc,
wxThread *threadToDelete = NULL);
// kill the thread unconditionally
wxThreadError Kill();
// suspend/resume/terminate
bool Suspend();
bool Resume();
void Cancel() { m_state = STATE_CANCELED; }
// thread state
void SetState(wxThreadState state) { m_state = state; }
wxThreadState GetState() const { return m_state; }
// thread priority
void SetPriority(unsigned int priority);
unsigned int GetPriority() const { return m_priority; }
// thread handle and id
HANDLE GetHandle() const { return m_hThread; }
DWORD GetId() const { return m_tid; }
// thread function
static THREAD_RETVAL THREAD_CALLCONV WinThreadStart(void *thread);
void KeepAlive()
{
if ( m_thread->IsDetached() )
::InterlockedIncrement(&m_nRef);
}
void LetDie()
{
if ( m_thread->IsDetached() && !::InterlockedDecrement(&m_nRef) )
delete m_thread;
}
private:
// the thread we're associated with
wxThread *m_thread;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?