threadpsx.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,725 行 · 第 1/4 页
CPP
1,725 行
/////////////////////////////////////////////////////////////////////////////
// Name: threadpsx.cpp
// Purpose: wxThread (Posix) Implementation
// Author: Original from Wolfram Gloger/Guilhem Lavaux
// Modified by: K. S. Sreeram (2002): POSIXified wxCondition, added wxSemaphore
// Created: 04/22/98
// RCS-ID: $Id: threadpsx.cpp,v 1.83.2.1 2006/01/17 19:17:24 JS Exp $
// Copyright: (c) Wolfram Gloger (1996, 1997)
// Guilhem Lavaux (1998)
// Vadim Zeitlin (1999-2002)
// Robert Roebling (1999)
// K. S. Sreeram (2002)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declaration
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "thread.h"
#endif
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#if wxUSE_THREADS
#include "wx/thread.h"
#include "wx/module.h"
#include "wx/utils.h"
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/dynarray.h"
#include "wx/timer.h"
#include "wx/stopwatch.h"
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <time.h>
#ifdef HAVE_SCHED_H
#include <sched.h>
#endif
#ifdef HAVE_THR_SETCONCURRENCY
#include <thread.h>
#endif
// we use wxFFile under Linux in GetCPUCount()
#ifdef __LINUX__
#include "wx/ffile.h"
// For setpriority.
#include <sys/time.h>
#include <sys/resource.h>
#endif
#ifdef __VMS
#define THR_ID(thr) ((long long)(thr)->GetId())
#else
#define THR_ID(thr) ((long)(thr)->GetId())
#endif
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// the possible states of the thread and transitions from them
enum wxThreadState
{
STATE_NEW, // didn't start execution yet (=> RUNNING)
STATE_RUNNING, // running (=> PAUSED or EXITED)
STATE_PAUSED, // suspended (=> RUNNING or EXITED)
STATE_EXITED // thread doesn't exist any more
};
// the exit value of a thread which has been cancelled
static const wxThread::ExitCode EXITCODE_CANCELLED = (wxThread::ExitCode)-1;
// trace mask for wxThread operations
#define TRACE_THREADS _T("thread")
// you can get additional debugging messages for the semaphore operations
#define TRACE_SEMA _T("semaphore")
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
static void ScheduleThreadForDeletion();
static void DeleteThread(wxThread *This);
// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------
// an (non owning) array of pointers to threads
WX_DEFINE_ARRAY_PTR(wxThread *, wxArrayThread);
// an entry for a thread we can wait for
// -----------------------------------------------------------------------------
// global data
// -----------------------------------------------------------------------------
// we keep the list of all threads created by the application to be able to
// terminate them on exit if there are some left - otherwise the process would
// be left in memory
static wxArrayThread gs_allThreads;
// the id of the main thread
static pthread_t gs_tidMain = (pthread_t)-1;
// the key for the pointer to the associated wxThread object
static pthread_key_t gs_keySelf;
// the number of threads which are being deleted - the program won't exit
// until there are any left
static size_t gs_nThreadsBeingDeleted = 0;
// a mutex to protect gs_nThreadsBeingDeleted
static wxMutex *gs_mutexDeleteThread = (wxMutex *)NULL;
// and a condition variable which will be signaled when all
// gs_nThreadsBeingDeleted will have been deleted
static wxCondition *gs_condAllDeleted = (wxCondition *)NULL;
// this mutex must be acquired before any call to a GUI function
// (it's not inside #if wxUSE_GUI because this file is compiled as part
// of wxBase)
static wxMutex *gs_mutexGui = NULL;
// when we wait for a thread to exit, we're blocking on a condition which the
// thread signals in its SignalExit() method -- but this condition can't be a
// member of the thread itself as a detached thread may delete itself at any
// moment and accessing the condition member of the thread after this would
// result in a disaster
//
// so instead we maintain a global list of the structs below for the threads
// we're interested in waiting on
// ============================================================================
// wxMutex implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxMutexInternal
// ----------------------------------------------------------------------------
// this is a simple wrapper around pthread_mutex_t which provides error
// checking
class wxMutexInternal
{
public:
wxMutexInternal(wxMutexType mutexType);
~wxMutexInternal();
wxMutexError Lock();
wxMutexError TryLock();
wxMutexError Unlock();
bool IsOk() const { return m_isOk; }
private:
pthread_mutex_t m_mutex;
bool m_isOk;
// wxConditionInternal uses our m_mutex
friend class wxConditionInternal;
};
#ifdef HAVE_PTHREAD_MUTEXATTR_T
// on some systems pthread_mutexattr_settype() is not in the headers (but it is
// in the library, otherwise we wouldn't compile this code at all)
extern "C" int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
#endif
wxMutexInternal::wxMutexInternal(wxMutexType mutexType)
{
int err;
switch ( mutexType )
{
case wxMUTEX_RECURSIVE:
// support recursive locks like Win32, i.e. a thread can lock a
// mutex which it had itself already locked
//
// unfortunately initialization of recursive mutexes is non
// portable, so try several methods
#ifdef HAVE_PTHREAD_MUTEXATTR_T
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
err = pthread_mutex_init(&m_mutex, &attr);
}
#elif defined(HAVE_PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
// we can use this only as initializer so we have to assign it
// first to a temp var - assigning directly to m_mutex wouldn't
// even compile
{
pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
m_mutex = mutex;
}
#else // no recursive mutexes
err = EINVAL;
#endif // HAVE_PTHREAD_MUTEXATTR_T/...
break;
default:
wxFAIL_MSG( _T("unknown mutex type") );
// fall through
case wxMUTEX_DEFAULT:
err = pthread_mutex_init(&m_mutex, NULL);
break;
}
m_isOk = err == 0;
if ( !m_isOk )
{
wxLogApiError( wxT("pthread_mutex_init()"), err);
}
}
wxMutexInternal::~wxMutexInternal()
{
if ( m_isOk )
{
int err = pthread_mutex_destroy(&m_mutex);
if ( err != 0 )
{
wxLogApiError( wxT("pthread_mutex_destroy()"), err);
}
}
}
wxMutexError wxMutexInternal::Lock()
{
int err = pthread_mutex_lock(&m_mutex);
switch ( err )
{
case EDEADLK:
// only error checking mutexes return this value and so it's an
// unexpected situation -- hence use assert, not wxLogDebug
wxFAIL_MSG( _T("mutex deadlock prevented") );
return wxMUTEX_DEAD_LOCK;
case EINVAL:
wxLogDebug(_T("pthread_mutex_lock(): mutex not initialized."));
break;
case 0:
return wxMUTEX_NO_ERROR;
default:
wxLogApiError(_T("pthread_mutex_lock()"), err);
}
return wxMUTEX_MISC_ERROR;
}
wxMutexError wxMutexInternal::TryLock()
{
int err = pthread_mutex_trylock(&m_mutex);
switch ( err )
{
case EBUSY:
// not an error: mutex is already locked, but we're prepared for
// this
return wxMUTEX_BUSY;
case EINVAL:
wxLogDebug(_T("pthread_mutex_trylock(): mutex not initialized."));
break;
case 0:
return wxMUTEX_NO_ERROR;
default:
wxLogApiError(_T("pthread_mutex_trylock()"), err);
}
return wxMUTEX_MISC_ERROR;
}
wxMutexError wxMutexInternal::Unlock()
{
int err = pthread_mutex_unlock(&m_mutex);
switch ( err )
{
case EPERM:
// we don't own the mutex
return wxMUTEX_UNLOCKED;
case EINVAL:
wxLogDebug(_T("pthread_mutex_unlock(): mutex not initialized."));
break;
case 0:
return wxMUTEX_NO_ERROR;
default:
wxLogApiError(_T("pthread_mutex_unlock()"), err);
}
return wxMUTEX_MISC_ERROR;
}
// ===========================================================================
// wxCondition implementation
// ===========================================================================
// ---------------------------------------------------------------------------
// wxConditionInternal
// ---------------------------------------------------------------------------
// this is a wrapper around pthread_cond_t associated with a wxMutex (and hence
// with a pthread_mutex_t)
class wxConditionInternal
{
public:
wxConditionInternal(wxMutex& mutex);
~wxConditionInternal();
bool IsOk() const { return m_isOk && m_mutex.IsOk(); }
wxCondError Wait();
wxCondError WaitTimeout(unsigned long milliseconds);
wxCondError Signal();
wxCondError Broadcast();
private:
// get the POSIX mutex associated with us
pthread_mutex_t *GetPMutex() const { return &m_mutex.m_internal->m_mutex; }
wxMutex& m_mutex;
pthread_cond_t m_cond;
bool m_isOk;
};
wxConditionInternal::wxConditionInternal(wxMutex& mutex)
: m_mutex(mutex)
{
int err = pthread_cond_init(&m_cond, NULL /* default attributes */);
m_isOk = err == 0;
if ( !m_isOk )
{
wxLogApiError(_T("pthread_cond_init()"), err);
}
}
wxConditionInternal::~wxConditionInternal()
{
if ( m_isOk )
{
int err = pthread_cond_destroy(&m_cond);
if ( err != 0 )
{
wxLogApiError(_T("pthread_cond_destroy()"), err);
}
}
}
wxCondError wxConditionInternal::Wait()
{
int err = pthread_cond_wait(&m_cond, GetPMutex());
if ( err != 0 )
{
wxLogApiError(_T("pthread_cond_wait()"), err);
return wxCOND_MISC_ERROR;
}
return wxCOND_NO_ERROR;
}
wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
{
wxLongLong curtime = wxGetLocalTimeMillis();
curtime += milliseconds;
wxLongLong temp = curtime / 1000;
int sec = temp.GetLo();
temp *= 1000;
temp = curtime - temp;
int millis = temp.GetLo();
timespec tspec;
tspec.tv_sec = sec;
tspec.tv_nsec = millis * 1000L * 1000L;
int err = pthread_cond_timedwait( &m_cond, GetPMutex(), &tspec );
switch ( err )
{
case ETIMEDOUT:
return wxCOND_TIMEOUT;
case 0:
return wxCOND_NO_ERROR;
default:
wxLogApiError(_T("pthread_cond_timedwait()"), err);
}
return wxCOND_MISC_ERROR;
}
wxCondError wxConditionInternal::Signal()
{
int err = pthread_cond_signal(&m_cond);
if ( err != 0 )
{
wxLogApiError(_T("pthread_cond_signal()"), err);
return wxCOND_MISC_ERROR;
}
return wxCOND_NO_ERROR;
}
wxCondError wxConditionInternal::Broadcast()
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?