⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 thread.cpp

📁 Wxpython Implemented on Windows CE, Source code
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/////////////////////////////////////////////////////////////////////////////
// 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(&current);
        // 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(&current);
        // 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 + -