📄 thread.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Name: thread.cpp
// Purpose: wxThread Implementation
// Author: Original from Wolfram Gloger/Guilhem Lavaux/Vadim Zeitlin
// Modified by: Stefan Csomor
// Created: 04/22/98
// RCS-ID: $Id: thread.cpp,v 1.5 2005/09/23 12:54:26 MR Exp $
// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
// Vadim Zeitlin (1999) , Stefan Csomor (2000)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#if defined(__BORLANDC__)
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#if wxUSE_THREADS
#include "wx/module.h"
#include "wx/thread.h"
#ifdef __WXMAC__
#include <Threads.h>
#include "wx/mac/uma.h"
#include "wx/mac/macnotfy.h"
#include <Timer.h>
#endif
#define INFINITE 0xFFFFFFFF
// ----------------------------------------------------------------------------
// 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
// ----------------------------------------------------------------------------
static ThreadID gs_idMainThread = kNoThreadID ;
static bool gs_waitingForThread = FALSE ;
size_t g_numberOfThreads = 0;
// ============================================================================
// MacOS implementation of thread classes
// ============================================================================
class wxMacStCritical
{
public :
wxMacStCritical()
{
if ( UMASystemIsInitialized() )
{
OSErr err = ThreadBeginCritical() ;
wxASSERT( err == noErr ) ;
}
}
~wxMacStCritical()
{
if ( UMASystemIsInitialized() )
{
OSErr err = ThreadEndCritical() ;
wxASSERT( err == noErr ) ;
}
}
};
// ----------------------------------------------------------------------------
// wxMutex implementation
// ----------------------------------------------------------------------------
class wxMutexInternal
{
public:
wxMutexInternal(wxMutexType WXUNUSED(mutexType))
{
m_owner = kNoThreadID ;
m_locked = 0;
}
~wxMutexInternal()
{
if ( m_locked > 0 )
{
wxLogDebug(_T("Warning: freeing a locked mutex (%ld locks)."), m_locked);
}
}
bool IsOk() const { return true; }
wxMutexError Lock() ;
wxMutexError TryLock() ;
wxMutexError Unlock();
public:
ThreadID m_owner ;
wxArrayLong m_waiters ;
long m_locked ;
};
wxMutexError wxMutexInternal::Lock()
{
wxMacStCritical critical ;
if ( UMASystemIsInitialized() )
{
OSErr err ;
ThreadID current = kNoThreadID;
err = ::MacGetCurrentThread(¤t);
// if we are not the owner, add this thread to the list of waiting threads, stop this thread
// and invoke the scheduler to continue executing the owner's thread
while ( m_owner != kNoThreadID && m_owner != current)
{
m_waiters.Add(current);
err = ::SetThreadStateEndCritical(kCurrentThreadID, kStoppedThreadState, m_owner);
err = ::ThreadBeginCritical();
wxASSERT( err == noErr ) ;
}
m_owner = current;
}
m_locked++;
return wxMUTEX_NO_ERROR;
}
wxMutexError wxMutexInternal::TryLock()
{
wxMacStCritical critical ;
if ( UMASystemIsInitialized() )
{
ThreadID current = kNoThreadID;
::MacGetCurrentThread(¤t);
// if we are not the owner, give an error back
if ( m_owner != kNoThreadID && m_owner != current )
return wxMUTEX_BUSY;
m_owner = current;
}
m_locked++;
return wxMUTEX_NO_ERROR;
}
wxMutexError wxMutexInternal::Unlock()
{
if ( UMASystemIsInitialized() )
{
OSErr err;
err = ::ThreadBeginCritical();
wxASSERT( err == noErr ) ;
if (m_locked > 0)
m_locked--;
// this mutex is not owned by anybody anmore
m_owner = kNoThreadID;
// now pass on to the first waiting thread
ThreadID firstWaiting = kNoThreadID;
bool found = false;
while (!m_waiters.IsEmpty() && !found)
{
firstWaiting = m_waiters[0];
err = ::SetThreadState(firstWaiting, kReadyThreadState, kNoThreadID);
// in case this was not successful (dead thread), we just loop on and reset the id
found = (err != threadNotFoundErr);
if ( !found )
firstWaiting = kNoThreadID ;
m_waiters.RemoveAt(0) ;
}
// now we have a valid firstWaiting thread, which has been scheduled to run next, just end the
// critical section and invoke the scheduler
err = ::SetThreadStateEndCritical(kCurrentThreadID, kReadyThreadState, firstWaiting);
}
else
{
if (m_locked > 0)
m_locked--;
}
return wxMUTEX_NO_ERROR;
}
// --------------------------------------------------------------------------
// wxSemaphore
// --------------------------------------------------------------------------
// TODO not yet implemented
class wxSemaphoreInternal
{
public:
wxSemaphoreInternal(int initialcount, int maxcount);
~wxSemaphoreInternal();
bool IsOk() const { return true ; }
wxSemaError Wait() { return WaitTimeout(INFINITE); }
wxSemaError TryWait() { return WaitTimeout(0); }
wxSemaError WaitTimeout(unsigned long milliseconds);
wxSemaError Post();
private:
};
wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
{
if ( maxcount == 0 )
{
// make it practically infinite
maxcount = INT_MAX;
}
}
wxSemaphoreInternal::~wxSemaphoreInternal()
{
}
wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
{
return wxSEMA_MISC_ERROR;
}
wxSemaError wxSemaphoreInternal::Post()
{
return wxSEMA_MISC_ERROR;
}
// ----------------------------------------------------------------------------
// wxCondition implementation
// ----------------------------------------------------------------------------
// TODO this is not yet completed
class wxConditionInternal
{
public:
wxConditionInternal(wxMutex& mutex) : m_mutex(mutex)
{
m_excessSignals = 0 ;
}
~wxConditionInternal()
{
}
bool IsOk() const { return m_mutex.IsOk() ; }
wxCondError Wait()
{
return WaitTimeout(0xFFFFFFFF );
}
wxCondError WaitTimeout(unsigned long msectimeout)
{
wxMacStCritical critical ;
if ( m_excessSignals > 0 )
{
--m_excessSignals ;
return wxCOND_NO_ERROR ;
}
else if ( msectimeout == 0 )
{
return wxCOND_MISC_ERROR ;
}
else
{
}
/*
waiters++;
// FIXME this should be MsgWaitForMultipleObjects() as well probably
DWORD rc = ::WaitForSingleObject(event, timeout);
waiters--;
return rc != WAIT_TIMEOUT;
*/
return wxCOND_NO_ERROR ;
}
wxCondError Signal()
{
wxMacStCritical critical ;
return wxCOND_NO_ERROR;
}
wxCondError Broadcast()
{
wxMacStCritical critical ;
return wxCOND_NO_ERROR;
}
wxArrayLong m_waiters ;
wxInt32 m_excessSignals ;
wxMutex& m_mutex;
};
// ----------------------------------------------------------------------------
// wxCriticalSection implementation
// ----------------------------------------------------------------------------
// it's implemented as a mutex on mac os, so it is defined in the headers
// ----------------------------------------------------------------------------
// wxThread implementation
// ----------------------------------------------------------------------------
// wxThreadInternal class
// ----------------------
class wxThreadInternal
{
public:
wxThreadInternal()
{
m_tid = kNoThreadID ;
m_state = STATE_NEW;
m_priority = WXTHREAD_DEFAULT_PRIORITY;
}
~wxThreadInternal()
{
}
void Free()
{
}
// create a new (suspended) thread (for the given thread object)
bool Create(wxThread *thread, unsigned int stackSize);
// 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; }
void SetResult( void *res ) { m_result = res ; }
void *GetResult() { return m_result ; }
// thread handle and id
ThreadID GetId() const { return m_tid; }
// thread function
static pascal void* MacThreadStart(wxThread* arg);
private:
wxThreadState m_state; // state, see wxThreadState enum
unsigned int m_priority; // thread priority in "wx" units
ThreadID m_tid; // thread id
void* m_result;
static ThreadEntryUPP s_threadEntry ;
};
static wxArrayPtrVoid s_threads ;
ThreadEntryUPP wxThreadInternal::s_threadEntry = NULL ;
pascal void* wxThreadInternal::MacThreadStart(wxThread *thread)
{
// first of all, check whether we hadn't been cancelled already
if ( thread->m_internal->GetState() == STATE_EXITED )
{
return (void*)-1;
}
void* rc = thread->Entry();
// enter m_critsect before changing the thread state
thread->m_critsect.Enter();
bool wasCancelled = thread->m_internal->GetState() == STATE_CANCELED;
thread->m_internal->SetState(STATE_EXITED);
thread->m_critsect.Leave();
thread->OnExit();
// if the thread was cancelled (from Delete()), then it the handle is still
// needed there
if ( thread->IsDetached() && !wasCancelled )
{
// auto delete
delete thread;
}
//else: the joinable threads handle will be closed when Wait() is done
return rc;
}
void wxThreadInternal::SetPriority(unsigned int priority)
{
// Priorities don't exist on Mac
}
bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize)
{
if ( s_threadEntry == NULL )
{
s_threadEntry = NewThreadEntryUPP( (ThreadEntryProcPtr) MacThreadStart ) ;
}
OSErr err = NewThread( kCooperativeThread,
s_threadEntry,
(void*) thread,
stackSize,
kNewSuspend,
&m_result,
&m_tid );
if ( err != noErr )
{
wxLogSysError(_("Can't create thread"));
return FALSE;
}
if ( m_priority != WXTHREAD_DEFAULT_PRIORITY )
{
SetPriority(m_priority);
}
m_state = STATE_NEW;
return TRUE;
}
bool wxThreadInternal::Suspend()
{
OSErr err ;
err = ::ThreadBeginCritical();
wxASSERT( err == noErr ) ;
if ( m_state != STATE_RUNNING )
{
err = ::ThreadEndCritical() ;
wxASSERT( err == noErr ) ;
wxLogSysError(_("Can not suspend thread %x"), m_tid);
return FALSE;
}
m_state = STATE_PAUSED;
err = ::SetThreadStateEndCritical(m_tid, kStoppedThreadState, kNoThreadID);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -