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

📄 thread.cpp

📁 Wxpython Implemented on Windows CE, Source code
💻 CPP
📖 第 1 页 / 共 4 页
字号:
// ----------------------------------------------------------------------------
// wxCriticalSection implementation
// ----------------------------------------------------------------------------

// XXX currently implemented as mutex in headers. Change to critical section.

// ----------------------------------------------------------------------------
// wxThread implementation
// ----------------------------------------------------------------------------

// wxThreadInternal class
// ----------------------

class wxThreadInternal
{
public:
    wxThreadInternal()
    {
        m_tid = kInvalidID;
        m_state = STATE_NEW;
        m_prio = WXTHREAD_DEFAULT_PRIORITY;
        m_notifyQueueId = kInvalidID;
        m_exitcode = 0;
        m_cancelled = false ;

        // set to true only when the thread starts waiting on m_semSuspend
        m_isPaused = false;

        // defaults for joinable threads
        m_shouldBeJoined = true;
        m_isDetached = false;
    }

    virtual ~wxThreadInternal()
    {
        if ( m_notifyQueueId)
        {
            MPDeleteQueue( m_notifyQueueId );
            m_notifyQueueId = kInvalidID ;
        }
    }

    // thread function
    static OSStatus MacThreadStart(void* arg);

    // create a new (suspended) thread (for the given thread object)
    bool Create(wxThread *thread, unsigned int stackSize);

    // thread actions

    // start the thread
    wxThreadError Run();

    // unblock the thread allowing it to run
    void SignalRun() { m_semRun.Post(); }

    // ask the thread to terminate
    void Wait();

    // go to sleep until Resume() is called
    void Pause();

    // resume the thread
    void Resume();

    // accessors
    // priority
    int GetPriority() const
    { return m_prio; }
    void SetPriority(int prio);

    // state
    wxThreadState GetState() const
    { return m_state; }
    void SetState(wxThreadState state)
    { m_state = state; }

    // Get the ID of this thread's underlying MP Services task.
    MPTaskID  GetId() const
    { return m_tid; }

    void SetCancelFlag()
    { m_cancelled = true; }

    bool WasCancelled() const
    { return m_cancelled; }

    // exit code
    void SetExitCode(wxThread::ExitCode exitcode)
    { m_exitcode = exitcode; }
    wxThread::ExitCode GetExitCode() const
    { return m_exitcode; }

    // the pause flag
    void SetReallyPaused(bool paused)
    { m_isPaused = paused; }
    bool IsReallyPaused() const
    { return m_isPaused; }

    // tell the thread that it is a detached one
    void Detach()
    {
        wxCriticalSectionLocker lock(m_csJoinFlag);

        m_shouldBeJoined = false;
        m_isDetached = true;
    }

private:
    // the thread we're associated with
    wxThread *      m_thread;

    MPTaskID        m_tid;                // thread id
    MPQueueID        m_notifyQueueId;    // its notification queue

    wxThreadState m_state;              // see wxThreadState enum
    int           m_prio;               // in wxWidgets units: from 0 to 100

    // this flag is set when the thread should terminate
    bool m_cancelled;

    // this flag is set when the thread is blocking on m_semSuspend
    bool m_isPaused;

    // the thread exit code - only used for joinable (!detached) threads and
    // is only valid after the thread termination
    wxThread::ExitCode m_exitcode;

    // many threads may call Wait(), but only one of them should call
    // pthread_join(), so we have to keep track of this
    wxCriticalSection m_csJoinFlag;
    bool m_shouldBeJoined;
    bool m_isDetached;

    // this semaphore is posted by Run() and the threads Entry() is not
    // called before it is done
    wxSemaphore m_semRun;

    // this one is signaled when the thread should resume after having been
    // Pause()d
    wxSemaphore m_semSuspend;
};

OSStatus wxThreadInternal::MacThreadStart(void *parameter)
{
    wxThread* thread = (wxThread*) parameter ;
    wxThreadInternal *pthread = thread->m_internal;

    // add to TLS so that This() will work
    verify_noerr( MPSetTaskStorageValue( gs_tlsForWXThread , (long) thread ) ) ;

    // have to declare this before pthread_cleanup_push() which defines a
    // block!
    bool dontRunAtAll;

    // wait for the semaphore to be posted from Run()
    pthread->m_semRun.Wait();

    // test whether we should run the run at all - may be it was deleted
    // before it started to Run()?
    {
        wxCriticalSectionLocker lock(thread->m_critsect);

        dontRunAtAll = pthread->GetState() == STATE_NEW &&
                       pthread->WasCancelled();
    }

    if ( !dontRunAtAll )
    {
        pthread->m_exitcode = thread->Entry();

        {
            wxCriticalSectionLocker lock(thread->m_critsect);
            pthread->SetState( STATE_EXITED );
        }
    }

    if ( dontRunAtAll )
    {
        if ( pthread->m_isDetached )
            delete thread;

        return -1;
    }
    else
    {
        // on Mac for the running code,
        // the correct thread termination is to return

        // terminate the thread
        thread->Exit( pthread->m_exitcode );

        return (OSStatus) NULL; // pthread->m_exitcode;
    }
}

bool wxThreadInternal::Create( wxThread *thread, unsigned int stackSize )
{
    wxASSERT_MSG( m_state == STATE_NEW && !m_tid,
                    wxT("Create()ing thread twice?") );

    OSStatus err = noErr;
    m_thread = thread;

    if ( m_notifyQueueId == kInvalidID )
    {
        OSStatus err = MPCreateQueue( &m_notifyQueueId );
        if (err != noErr)
        {
            wxLogSysError( wxT("Cant create the thread event queue") );

            return false;
        }
    }

    m_state = STATE_NEW;

    err = MPCreateTask(
        MacThreadStart, (void*)m_thread, stackSize,
        m_notifyQueueId, &m_exitcode, 0, 0, &m_tid );

    if (err != noErr)
    {
        wxLogSysError( wxT("Can't create thread") );

        return false;
    }

    if ( m_prio != WXTHREAD_DEFAULT_PRIORITY )
        SetPriority( m_prio );

    return true;
}

void wxThreadInternal::SetPriority( int priority )
{
    m_prio = priority;

    if (m_tid)
    {
        // Mac priorities range from 1 to 10,000, with a default of 100.
        // wxWidgets priorities range from 0 to 100 with a default of 50.
        // We can map wxWidgets to Mac priorities easily by assuming
        // the former uses a logarithmic scale.
        const unsigned int macPriority = (int)( exp( priority / 25.0 * log( 10.0)) + 0.5);

        MPSetTaskWeight( m_tid, macPriority );
    }
}

wxThreadError wxThreadInternal::Run()
{
    wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
                 wxT("thread may only be started once after Create()") );

    SetState( STATE_RUNNING );

    // wake up threads waiting for our start
    SignalRun();

    return wxTHREAD_NO_ERROR;
}

void wxThreadInternal::Wait()
{
   wxCHECK_RET( !m_isDetached, wxT("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() )
    {
        // give the thread we're waiting for chance to do the GUI call
        // it might be in, we don't do this conditionally as the to be waited on
        // thread might have to acquire the mutex later but before terminating
        if ( wxGuiOwnedByMainThread() )
            wxMutexGuiLeave();
    }

    {
        wxCriticalSectionLocker lock(m_csJoinFlag);

        if ( m_shouldBeJoined )
        {
            void *param1, *param2, *rc;

            OSStatus err = MPWaitOnQueue(
                m_notifyQueueId,
                &param1,
                &param2,
                &rc,
                kDurationForever );
            if (err != noErr)
            {
                wxLogSysError( wxT( "Cannot wait for thread termination."));
                rc = (void*) -1;
            }

            // actually param1 would be the address of m_exitcode
            // but we don't need this here
            m_exitcode = rc;

            m_shouldBeJoined = false;
        }
    }
}

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().") );

    // 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() )
    {
        // wake up Pause()
        m_semSuspend.Post();

        // reset the flag
        SetReallyPaused( false );
    }

    SetState( STATE_RUNNING );
}

// static functions
// ----------------

wxThread *wxThread::This()
{
    wxThread* thr = (wxThread*) MPGetTaskStorageValue( gs_tlsForWXThread ) ;

    return thr;
}

bool wxThread::IsMain()
{
    return GetCurrentId() == gs_idMainThread || gs_idMainThread == kInvalidID ;
}

#ifdef Yield
#undef Yield
#endif

void wxThread::Yield()
{
#if TARGET_API_MAC_OSX
    CFRunLoopRunInMode( kCFRunLoopDefaultMode , 0 , true ) ;
#endif

    MPYield();
}

void wxThread::Sleep( unsigned long milliseconds )
{
    AbsoluteTime wakeup = AddDurationToAbsolute( milliseconds, UpTime() );
    MPDelayUntil( &wakeup );
}

int wxThread::GetCPUCount()
{
    return MPProcessors();
}

unsigned long wxThread::GetCurrentId()
{
    return (unsigned long)MPCurrentTaskID();
}

bool wxThread::SetConcurrency( size_t level )
{
    // Cannot be set in MacOS.
    return false;
}

wxThread::wxThread( wxThreadKind kind )
{
    g_numberOfThreads++;
    m_internal = new wxThreadInternal();

    m_isDetached = (kind == wxTHREAD_DETACHED);
}

wxThread::~wxThread()
{
    wxASSERT_MSG( g_numberOfThreads>0 , wxT("More threads deleted than created.") ) ;

    g_numberOfThreads--;

#ifdef __WXDEBUG__
    m_critsect.Enter();

    // check that the thread either exited or couldn't be created
    if ( m_internal->GetState() != STATE_EXITED &&
         m_internal->GetState() != STATE_NEW )
    {
        wxLogDebug(
            wxT("The thread %ld is being destroyed although it is still running! The application may crash."),
            GetId() );
    }

    m_critsect.Leave();
#endif

    wxDELETE( m_internal ) ;
}

wxThreadError wxThread::Create( unsigned int stackSize )
{
    wxCriticalSectionLocker lock(m_critsect);

    if ( m_isDetached )
        m_internal->Detach() ;

    if ( !m_internal->Create(this, stackSize) )
    {
        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();
}

// -----------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -