joinable and detached POSIX threads (not fully tested yet)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@4769 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -8,6 +8,25 @@ much easier to share common data between several threads, it also makes much
|
|||||||
easier to shoot oneself in the foot, so careful use of synchronization objects
|
easier to shoot oneself in the foot, so careful use of synchronization objects
|
||||||
such as \helpref{mutexes}{wxmutex} and/or \helpref{critical sections}{wxcriticalsection} is recommended.
|
such as \helpref{mutexes}{wxmutex} and/or \helpref{critical sections}{wxcriticalsection} is recommended.
|
||||||
|
|
||||||
|
There are two types of threads in wxWindows: {\it detached} and {\it joinable}
|
||||||
|
ones, just as in POSIX thread API (but unlike Win32 threads where all threads
|
||||||
|
are joinable). The difference between the two is that only joinbale threads
|
||||||
|
can return a return code - it is returned by Wait() function. The detached
|
||||||
|
threads (default) can not be waited for.
|
||||||
|
|
||||||
|
You shouldn't hurry to create all the threads joinable, however, because this
|
||||||
|
has a disadvantage as well: you {\bf must} Wait() for a joinable thread of the
|
||||||
|
system resources used by it will never be freed and you also must delete the
|
||||||
|
corresponding wxThread object yourself, while detached threads are of the
|
||||||
|
"fire-and-forget" kind: you only have to start a detached thread and it will
|
||||||
|
terminate and destroy itself.
|
||||||
|
|
||||||
|
This means, of course, that all detached threads {\bf must} be created on the
|
||||||
|
heap because the thread will call {\tt delete this;} upon termination. The
|
||||||
|
joinable threads may be created on stack (don't create global thread objects
|
||||||
|
because they allocate memory in their constructor which is a badthing to do),
|
||||||
|
although usually they will be created on the heap as well.
|
||||||
|
|
||||||
\wxheading{Derived from}
|
\wxheading{Derived from}
|
||||||
|
|
||||||
None.
|
None.
|
||||||
@@ -84,6 +103,10 @@ created. Moreover, it must be called if \helpref{Create}{wxthreadcreate} or
|
|||||||
occupied by the thread object (it will be done in the destructor for joinable
|
occupied by the thread object (it will be done in the destructor for joinable
|
||||||
threads).
|
threads).
|
||||||
|
|
||||||
|
Delete() may be called for thread in any state: running, paused or even not yet created. Moreover,
|
||||||
|
it must be called if \helpref{Create}{wxthreadcreate} or \helpref{Run}{wxthreadrun} fail to free
|
||||||
|
the memory occupied by the thread object.
|
||||||
|
|
||||||
For detached threads Delete() will also delete the C++ thread object, but it
|
For detached threads Delete() will also delete the C++ thread object, but it
|
||||||
will not do this for joinable ones.
|
will not do this for joinable ones.
|
||||||
|
|
||||||
|
@@ -8,7 +8,10 @@ wxWindows provides a complete set of classes encapsulating objects necessary in
|
|||||||
multithreaded (MT) programs: the \helpref{thread}{wxthread} class itself and different
|
multithreaded (MT) programs: the \helpref{thread}{wxthread} class itself and different
|
||||||
synchronization objects: \helpref{mutexes}{wxmutex} and
|
synchronization objects: \helpref{mutexes}{wxmutex} and
|
||||||
\helpref{critical sections}{wxcriticalsection} with
|
\helpref{critical sections}{wxcriticalsection} with
|
||||||
\helpref{conditions}{wxcondition}.
|
\helpref{conditions}{wxcondition}. The thread API in wxWindows resembles to
|
||||||
|
POSIX1.c threads API (a.k.a. pthreads), although several functions have
|
||||||
|
different names and some features inspired by Win32 thread API are there as
|
||||||
|
well.
|
||||||
|
|
||||||
These classes will hopefully make writing MT programs easier and they also
|
These classes will hopefully make writing MT programs easier and they also
|
||||||
provide some extra error checking (compared to the native (be it Win32 or Posix)
|
provide some extra error checking (compared to the native (be it Win32 or Posix)
|
||||||
|
@@ -16,13 +16,6 @@
|
|||||||
#pragma interface "textctrl.h"
|
#pragma interface "textctrl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// can we use RICHEDIT class for wxTextCtrl implementation?
|
|
||||||
#if defined(__WIN95__) && !defined(__TWIN32__) && !defined(__WXWINE__)
|
|
||||||
#define wxUSE_RICHEDIT 1
|
|
||||||
#else
|
|
||||||
#define wxUSE_RICHEDIT 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class WXDLLEXPORT wxTextCtrl : public wxTextCtrlBase
|
class WXDLLEXPORT wxTextCtrl : public wxTextCtrlBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@@ -40,21 +40,21 @@
|
|||||||
|
|
||||||
enum wxMutexError
|
enum wxMutexError
|
||||||
{
|
{
|
||||||
wxMUTEX_NO_ERROR = 0,
|
wxMUTEX_NO_ERROR = 0,
|
||||||
wxMUTEX_DEAD_LOCK, // Mutex has been already locked by THE CALLING thread
|
wxMUTEX_DEAD_LOCK, // Mutex has been already locked by THE CALLING thread
|
||||||
wxMUTEX_BUSY, // Mutex has been already locked by ONE thread
|
wxMUTEX_BUSY, // Mutex has been already locked by ONE thread
|
||||||
wxMUTEX_UNLOCKED,
|
wxMUTEX_UNLOCKED,
|
||||||
wxMUTEX_MISC_ERROR
|
wxMUTEX_MISC_ERROR
|
||||||
};
|
};
|
||||||
|
|
||||||
enum wxThreadError
|
enum wxThreadError
|
||||||
{
|
{
|
||||||
wxTHREAD_NO_ERROR = 0, // No error
|
wxTHREAD_NO_ERROR = 0, // No error
|
||||||
wxTHREAD_NO_RESOURCE, // No resource left to create a new thread
|
wxTHREAD_NO_RESOURCE, // No resource left to create a new thread
|
||||||
wxTHREAD_RUNNING, // The thread is already running
|
wxTHREAD_RUNNING, // The thread is already running
|
||||||
wxTHREAD_NOT_RUNNING, // The thread isn't running
|
wxTHREAD_NOT_RUNNING, // The thread isn't running
|
||||||
wxTHREAD_KILLED, // Thread we waited for had to be killed
|
wxTHREAD_KILLED, // Thread we waited for had to be killed
|
||||||
wxTHREAD_MISC_ERROR // Some other error
|
wxTHREAD_MISC_ERROR // Some other error
|
||||||
};
|
};
|
||||||
|
|
||||||
enum wxThreadKind
|
enum wxThreadKind
|
||||||
@@ -106,7 +106,7 @@ protected:
|
|||||||
wxMutex& operator=(const wxMutex&);
|
wxMutex& operator=(const wxMutex&);
|
||||||
|
|
||||||
int m_locked;
|
int m_locked;
|
||||||
wxMutexInternal *p_internal;
|
wxMutexInternal *m_internal;
|
||||||
};
|
};
|
||||||
|
|
||||||
// a helper class which locks the mutex in the ctor and unlocks it in the dtor:
|
// a helper class which locks the mutex in the ctor and unlocks it in the dtor:
|
||||||
@@ -213,28 +213,32 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Condition handler.
|
// Condition variable: allows to block the thread execution until something
|
||||||
|
// happens (== condition is signaled)
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
class wxConditionInternal;
|
class wxConditionInternal;
|
||||||
class WXDLLEXPORT wxCondition
|
class WXDLLEXPORT wxCondition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// constructor & destructor
|
// constructor & destructor
|
||||||
wxCondition();
|
wxCondition();
|
||||||
~wxCondition();
|
~wxCondition();
|
||||||
|
|
||||||
// Waits indefinitely.
|
// wait until the condition is signaled
|
||||||
void Wait(wxMutex& mutex);
|
// waits indefinitely.
|
||||||
// Waits until a signal is raised or the timeout is elapsed.
|
void Wait();
|
||||||
bool Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec);
|
// waits until a signal is raised or the timeout elapses
|
||||||
// Raises a signal: only one "Waiter" is released.
|
bool Wait(unsigned long sec, unsigned long nsec);
|
||||||
void Signal();
|
|
||||||
// Broadcasts to all "Waiters".
|
// signal the condition
|
||||||
void Broadcast();
|
// wakes up one (and only one) of the waiting threads
|
||||||
|
void Signal();
|
||||||
|
// wakes up all threads waiting onthis condition
|
||||||
|
void Broadcast();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wxConditionInternal *p_internal;
|
wxConditionInternal *m_internal;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -381,7 +385,7 @@ private:
|
|||||||
friend class wxThreadInternal;
|
friend class wxThreadInternal;
|
||||||
|
|
||||||
// the (platform-dependent) thread class implementation
|
// the (platform-dependent) thread class implementation
|
||||||
wxThreadInternal *p_internal;
|
wxThreadInternal *m_internal;
|
||||||
|
|
||||||
// protects access to any methods of wxThreadInternal object
|
// protects access to any methods of wxThreadInternal object
|
||||||
wxCriticalSection m_critsect;
|
wxCriticalSection m_critsect;
|
||||||
|
@@ -31,9 +31,10 @@
|
|||||||
|
|
||||||
//#define TEST_ARRAYS
|
//#define TEST_ARRAYS
|
||||||
//#define TEST_LOG
|
//#define TEST_LOG
|
||||||
//#define TEST_THREADS
|
//#define TEST_STRINGS
|
||||||
|
#define TEST_THREADS
|
||||||
//#define TEST_TIME
|
//#define TEST_TIME
|
||||||
#define TEST_LONGLONG
|
//#define TEST_LONGLONG
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// implementation
|
// implementation
|
||||||
@@ -151,7 +152,7 @@ wxThread::ExitCode MyJoinableThread::Entry()
|
|||||||
class MyDetachedThread : public wxThread
|
class MyDetachedThread : public wxThread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MyDetachedThread(char ch) { m_ch = ch; Create(); }
|
MyDetachedThread(size_t n, char ch) { m_n = n; m_ch = ch; Create(); }
|
||||||
|
|
||||||
// thread execution starts here
|
// thread execution starts here
|
||||||
virtual ExitCode Entry();
|
virtual ExitCode Entry();
|
||||||
@@ -160,7 +161,8 @@ public:
|
|||||||
virtual void OnExit();
|
virtual void OnExit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char m_ch;
|
size_t m_n; // number of characters to write
|
||||||
|
char m_ch; // character to write
|
||||||
};
|
};
|
||||||
|
|
||||||
wxThread::ExitCode MyDetachedThread::Entry()
|
wxThread::ExitCode MyDetachedThread::Entry()
|
||||||
@@ -173,8 +175,7 @@ wxThread::ExitCode MyDetachedThread::Entry()
|
|||||||
gs_counter++;
|
gs_counter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const size_t nIter = 10;
|
for ( size_t n = 0; n < m_n; n++ )
|
||||||
for ( size_t n = 0; n < nIter; n++ )
|
|
||||||
{
|
{
|
||||||
if ( TestDestroy() )
|
if ( TestDestroy() )
|
||||||
break;
|
break;
|
||||||
@@ -190,11 +191,86 @@ wxThread::ExitCode MyDetachedThread::Entry()
|
|||||||
|
|
||||||
void MyDetachedThread::OnExit()
|
void MyDetachedThread::OnExit()
|
||||||
{
|
{
|
||||||
|
wxLogTrace("thread", "Thread %ld is in OnExit", GetId());
|
||||||
|
|
||||||
wxCriticalSectionLocker lock(gs_critsect);
|
wxCriticalSectionLocker lock(gs_critsect);
|
||||||
if ( !--gs_counter )
|
if ( !--gs_counter )
|
||||||
gs_cond.Signal();
|
gs_cond.Signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestDetachedThreads()
|
||||||
|
{
|
||||||
|
puts("*** Testing detached threads ***");
|
||||||
|
|
||||||
|
static const size_t nThreads = 3;
|
||||||
|
MyDetachedThread *threads[nThreads];
|
||||||
|
size_t n;
|
||||||
|
for ( n = 0; n < nThreads; n++ )
|
||||||
|
{
|
||||||
|
threads[n] = new MyDetachedThread(10, 'A' + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
threads[0]->SetPriority(WXTHREAD_MIN_PRIORITY);
|
||||||
|
threads[1]->SetPriority(WXTHREAD_MAX_PRIORITY);
|
||||||
|
|
||||||
|
for ( n = 0; n < nThreads; n++ )
|
||||||
|
{
|
||||||
|
threads[n]->Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until all threads terminate
|
||||||
|
gs_cond.Wait();
|
||||||
|
|
||||||
|
puts("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestJoinableThreads()
|
||||||
|
{
|
||||||
|
puts("*** Testing a joinable thread (a loooong calculation...) ***");
|
||||||
|
|
||||||
|
// calc 10! in the background
|
||||||
|
MyJoinableThread thread(10);
|
||||||
|
thread.Run();
|
||||||
|
|
||||||
|
printf("\nThread terminated with exit code %lu.\n",
|
||||||
|
(unsigned long)thread.Wait());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestThreadSuspend()
|
||||||
|
{
|
||||||
|
MyDetachedThread *thread = new MyDetachedThread(30, 'X');
|
||||||
|
|
||||||
|
thread->Run();
|
||||||
|
|
||||||
|
// this is for this demo only, in a real life program we'd use another
|
||||||
|
// condition variable which would be signaled from wxThread::Entry() to
|
||||||
|
// tell us that the thread really started running - but here just wait a
|
||||||
|
// bit and hope that it will be enough (the problem is, of course, that
|
||||||
|
// the thread might still not run when we call Pause() which will result
|
||||||
|
// in an error)
|
||||||
|
wxThread::Sleep(300);
|
||||||
|
|
||||||
|
for ( size_t n = 0; n < 3; n++ )
|
||||||
|
{
|
||||||
|
thread->Pause();
|
||||||
|
|
||||||
|
puts("\nThread suspended");
|
||||||
|
if ( n > 0 )
|
||||||
|
{
|
||||||
|
// don't sleep but resume immediately the first time
|
||||||
|
wxThread::Sleep(300);
|
||||||
|
}
|
||||||
|
puts("Going to resume the thread");
|
||||||
|
|
||||||
|
thread->Resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait until the thread terminates
|
||||||
|
gs_cond.Wait();
|
||||||
|
|
||||||
|
puts("");
|
||||||
|
}
|
||||||
|
|
||||||
#endif // TEST_THREADS
|
#endif // TEST_THREADS
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -216,6 +292,64 @@ void PrintArray(const char* name, const wxArrayString& array)
|
|||||||
|
|
||||||
#endif // TEST_ARRAYS
|
#endif // TEST_ARRAYS
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// strings
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef TEST_STRINGS
|
||||||
|
|
||||||
|
#include "wx/timer.h"
|
||||||
|
|
||||||
|
void TestString()
|
||||||
|
{
|
||||||
|
wxStopWatch sw;
|
||||||
|
|
||||||
|
wxString a, b, c;
|
||||||
|
|
||||||
|
a.reserve (128);
|
||||||
|
b.reserve (128);
|
||||||
|
c.reserve (128);
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000000; ++i)
|
||||||
|
{
|
||||||
|
a = "Hello";
|
||||||
|
b = " world";
|
||||||
|
c = "! How'ya doin'?";
|
||||||
|
a += b;
|
||||||
|
a += c;
|
||||||
|
c = "Hello world! What's up?";
|
||||||
|
if (c != a)
|
||||||
|
c = "Doh!";
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ("TestString elapsed time: %ld\n", sw.Time());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPChar()
|
||||||
|
{
|
||||||
|
wxStopWatch sw;
|
||||||
|
|
||||||
|
char a [128];
|
||||||
|
char b [128];
|
||||||
|
char c [128];
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000000; ++i)
|
||||||
|
{
|
||||||
|
strcpy (a, "Hello");
|
||||||
|
strcpy (b, " world");
|
||||||
|
strcpy (c, "! How'ya doin'?");
|
||||||
|
strcat (a, b);
|
||||||
|
strcat (a, c);
|
||||||
|
strcpy (c, "Hello world! What's up?");
|
||||||
|
if (strcmp (c, a) == 0)
|
||||||
|
strcpy (c, "Doh!");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf ("TestPChar elapsed time: %ld\n", sw.Time());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // TEST_STRINGS
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// entry point
|
// entry point
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -227,6 +361,11 @@ int main(int argc, char **argv)
|
|||||||
fprintf(stderr, "Failed to initialize the wxWindows library, aborting.");
|
fprintf(stderr, "Failed to initialize the wxWindows library, aborting.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TEST_STRINGS
|
||||||
|
TestPChar();
|
||||||
|
TestString();
|
||||||
|
#endif // TEST_STRINGS
|
||||||
|
|
||||||
#ifdef TEST_ARRAYS
|
#ifdef TEST_ARRAYS
|
||||||
wxArrayString a1;
|
wxArrayString a1;
|
||||||
a1.Add("tiger");
|
a1.Add("tiger");
|
||||||
@@ -279,38 +418,15 @@ int main(int argc, char **argv)
|
|||||||
#endif // TEST_LOG
|
#endif // TEST_LOG
|
||||||
|
|
||||||
#ifdef TEST_THREADS
|
#ifdef TEST_THREADS
|
||||||
puts("Testing detached threads...");
|
if ( argc > 1 && argv[1][0] == 't' )
|
||||||
|
wxLog::AddTraceMask("thread");
|
||||||
|
|
||||||
static const size_t nThreads = 3;
|
TestThreadSuspend();
|
||||||
MyDetachedThread *threads[nThreads];
|
if ( 0 )
|
||||||
size_t n;
|
|
||||||
for ( n = 0; n < nThreads; n++ )
|
|
||||||
{
|
{
|
||||||
threads[n] = new MyDetachedThread('A' + n);
|
TestDetachedThreads();
|
||||||
|
TestJoinableThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
threads[0]->SetPriority(WXTHREAD_MIN_PRIORITY);
|
|
||||||
threads[1]->SetPriority(WXTHREAD_MAX_PRIORITY);
|
|
||||||
|
|
||||||
for ( n = 0; n < nThreads; n++ )
|
|
||||||
{
|
|
||||||
threads[n]->Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until all threads terminate
|
|
||||||
wxMutex mutex;
|
|
||||||
mutex.Lock();
|
|
||||||
gs_cond.Wait(mutex);
|
|
||||||
mutex.Unlock();
|
|
||||||
|
|
||||||
puts("\n\nTesting a joinable thread used for a loooong calculation...");
|
|
||||||
|
|
||||||
// calc 10! in the background
|
|
||||||
MyJoinableThread thread(10);
|
|
||||||
thread.Run();
|
|
||||||
|
|
||||||
printf("\nThread terminated with exit code %lu.\n",
|
|
||||||
(unsigned long)thread.Wait());
|
|
||||||
#endif // TEST_THREADS
|
#endif // TEST_THREADS
|
||||||
|
|
||||||
#ifdef TEST_LONGLONG
|
#ifdef TEST_LONGLONG
|
||||||
|
@@ -104,9 +104,9 @@ public:
|
|||||||
|
|
||||||
wxMutex::wxMutex()
|
wxMutex::wxMutex()
|
||||||
{
|
{
|
||||||
p_internal = new wxMutexInternal;
|
m_internal = new wxMutexInternal;
|
||||||
p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
|
m_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
|
||||||
if ( !p_internal->p_mutex )
|
if ( !m_internal->p_mutex )
|
||||||
{
|
{
|
||||||
wxLogSysError(_("Can not create mutex."));
|
wxLogSysError(_("Can not create mutex."));
|
||||||
}
|
}
|
||||||
@@ -118,14 +118,14 @@ wxMutex::~wxMutex()
|
|||||||
{
|
{
|
||||||
if (m_locked > 0)
|
if (m_locked > 0)
|
||||||
wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked);
|
wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked);
|
||||||
CloseHandle(p_internal->p_mutex);
|
CloseHandle(m_internal->p_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMutexError wxMutex::Lock()
|
wxMutexError wxMutex::Lock()
|
||||||
{
|
{
|
||||||
DWORD ret;
|
DWORD ret;
|
||||||
|
|
||||||
ret = WaitForSingleObject(p_internal->p_mutex, INFINITE);
|
ret = WaitForSingleObject(m_internal->p_mutex, INFINITE);
|
||||||
switch ( ret )
|
switch ( ret )
|
||||||
{
|
{
|
||||||
case WAIT_ABANDONED:
|
case WAIT_ABANDONED:
|
||||||
@@ -152,7 +152,7 @@ wxMutexError wxMutex::TryLock()
|
|||||||
{
|
{
|
||||||
DWORD ret;
|
DWORD ret;
|
||||||
|
|
||||||
ret = WaitForSingleObject(p_internal->p_mutex, 0);
|
ret = WaitForSingleObject(m_internal->p_mutex, 0);
|
||||||
if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
|
if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
|
||||||
return wxMUTEX_BUSY;
|
return wxMUTEX_BUSY;
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ wxMutexError wxMutex::Unlock()
|
|||||||
if (m_locked > 0)
|
if (m_locked > 0)
|
||||||
m_locked--;
|
m_locked--;
|
||||||
|
|
||||||
BOOL ret = ReleaseMutex(p_internal->p_mutex);
|
BOOL ret = ReleaseMutex(m_internal->p_mutex);
|
||||||
if ( ret == 0 )
|
if ( ret == 0 )
|
||||||
{
|
{
|
||||||
wxLogSysError(_("Couldn't release a mutex"));
|
wxLogSysError(_("Couldn't release a mutex"));
|
||||||
@@ -197,16 +197,14 @@ public:
|
|||||||
waiters = 0;
|
waiters = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wait(wxMutex& mutex, DWORD timeout)
|
bool Wait(DWORD timeout)
|
||||||
{
|
{
|
||||||
mutex.Unlock();
|
|
||||||
waiters++;
|
waiters++;
|
||||||
|
|
||||||
// FIXME this should be MsgWaitForMultipleObjects() as well probably
|
// FIXME this should be MsgWaitForMultipleObjects() as well probably
|
||||||
DWORD rc = ::WaitForSingleObject(event, timeout);
|
DWORD rc = ::WaitForSingleObject(event, timeout);
|
||||||
|
|
||||||
waiters--;
|
waiters--;
|
||||||
mutex.Lock();
|
|
||||||
|
|
||||||
return rc != WAIT_TIMEOUT;
|
return rc != WAIT_TIMEOUT;
|
||||||
}
|
}
|
||||||
@@ -228,24 +226,23 @@ public:
|
|||||||
|
|
||||||
wxCondition::wxCondition()
|
wxCondition::wxCondition()
|
||||||
{
|
{
|
||||||
p_internal = new wxConditionInternal;
|
m_internal = new wxConditionInternal;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxCondition::~wxCondition()
|
wxCondition::~wxCondition()
|
||||||
{
|
{
|
||||||
delete p_internal;
|
delete m_internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxCondition::Wait(wxMutex& mutex)
|
void wxCondition::Wait()
|
||||||
{
|
{
|
||||||
(void)p_internal->Wait(mutex, INFINITE);
|
(void)m_internal->Wait(INFINITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxCondition::Wait(wxMutex& mutex,
|
bool wxCondition::Wait(unsigned long sec,
|
||||||
unsigned long sec,
|
|
||||||
unsigned long nsec)
|
unsigned long nsec)
|
||||||
{
|
{
|
||||||
return p_internal->Wait(mutex, sec*1000 + nsec/1000000);
|
return m_internal->Wait(sec*1000 + nsec/1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxCondition::Signal()
|
void wxCondition::Signal()
|
||||||
@@ -255,7 +252,7 @@ void wxCondition::Signal()
|
|||||||
// someone waits on it. In any case, the system will return it to a non
|
// someone waits on it. In any case, the system will return it to a non
|
||||||
// signalled state afterwards. If multiple threads are waiting, only one
|
// signalled state afterwards. If multiple threads are waiting, only one
|
||||||
// will be woken up.
|
// will be woken up.
|
||||||
if ( !::SetEvent(p_internal->event) )
|
if ( !::SetEvent(m_internal->event) )
|
||||||
{
|
{
|
||||||
wxLogLastError("SetEvent");
|
wxLogLastError("SetEvent");
|
||||||
}
|
}
|
||||||
@@ -266,7 +263,7 @@ void wxCondition::Broadcast()
|
|||||||
// this works because all these threads are already waiting and so each
|
// this works because all these threads are already waiting and so each
|
||||||
// SetEvent() inside Signal() is really a PulseEvent() because the event
|
// SetEvent() inside Signal() is really a PulseEvent() because the event
|
||||||
// state is immediately returned to non-signaled
|
// state is immediately returned to non-signaled
|
||||||
for ( int i = 0; i < p_internal->waiters; i++ )
|
for ( int i = 0; i < m_internal->waiters; i++ )
|
||||||
{
|
{
|
||||||
Signal();
|
Signal();
|
||||||
}
|
}
|
||||||
@@ -378,8 +375,8 @@ DWORD wxThreadInternal::WinThreadStart(wxThread *thread)
|
|||||||
|
|
||||||
// enter m_critsect before changing the thread state
|
// enter m_critsect before changing the thread state
|
||||||
thread->m_critsect.Enter();
|
thread->m_critsect.Enter();
|
||||||
bool wasCancelled = thread->p_internal->GetState() == STATE_CANCELED;
|
bool wasCancelled = thread->m_internal->GetState() == STATE_CANCELED;
|
||||||
thread->p_internal->SetState(STATE_EXITED);
|
thread->m_internal->SetState(STATE_EXITED);
|
||||||
thread->m_critsect.Leave();
|
thread->m_critsect.Leave();
|
||||||
|
|
||||||
thread->OnExit();
|
thread->OnExit();
|
||||||
@@ -535,14 +532,14 @@ void wxThread::Sleep(unsigned long milliseconds)
|
|||||||
|
|
||||||
wxThread::wxThread(wxThreadKind kind)
|
wxThread::wxThread(wxThreadKind kind)
|
||||||
{
|
{
|
||||||
p_internal = new wxThreadInternal();
|
m_internal = new wxThreadInternal();
|
||||||
|
|
||||||
m_isDetached = kind == wxTHREAD_DETACHED;
|
m_isDetached = kind == wxTHREAD_DETACHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxThread::~wxThread()
|
wxThread::~wxThread()
|
||||||
{
|
{
|
||||||
delete p_internal;
|
delete m_internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create/start thread
|
// create/start thread
|
||||||
@@ -552,7 +549,7 @@ wxThreadError wxThread::Create()
|
|||||||
{
|
{
|
||||||
wxCriticalSectionLocker lock(m_critsect);
|
wxCriticalSectionLocker lock(m_critsect);
|
||||||
|
|
||||||
if ( !p_internal->Create(this) )
|
if ( !m_internal->Create(this) )
|
||||||
return wxTHREAD_NO_RESOURCE;
|
return wxTHREAD_NO_RESOURCE;
|
||||||
|
|
||||||
return wxTHREAD_NO_ERROR;
|
return wxTHREAD_NO_ERROR;
|
||||||
@@ -562,7 +559,7 @@ wxThreadError wxThread::Run()
|
|||||||
{
|
{
|
||||||
wxCriticalSectionLocker lock(m_critsect);
|
wxCriticalSectionLocker lock(m_critsect);
|
||||||
|
|
||||||
if ( p_internal->GetState() != STATE_NEW )
|
if ( m_internal->GetState() != STATE_NEW )
|
||||||
{
|
{
|
||||||
// actually, it may be almost any state at all, not only STATE_RUNNING
|
// actually, it may be almost any state at all, not only STATE_RUNNING
|
||||||
return wxTHREAD_RUNNING;
|
return wxTHREAD_RUNNING;
|
||||||
@@ -579,14 +576,14 @@ wxThreadError wxThread::Pause()
|
|||||||
{
|
{
|
||||||
wxCriticalSectionLocker lock(m_critsect);
|
wxCriticalSectionLocker lock(m_critsect);
|
||||||
|
|
||||||
return p_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
|
return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxThreadError wxThread::Resume()
|
wxThreadError wxThread::Resume()
|
||||||
{
|
{
|
||||||
wxCriticalSectionLocker lock(m_critsect);
|
wxCriticalSectionLocker lock(m_critsect);
|
||||||
|
|
||||||
return p_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
|
return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// stopping thread
|
// stopping thread
|
||||||
@@ -603,7 +600,7 @@ wxThread::ExitCode wxThread::Wait()
|
|||||||
|
|
||||||
(void)Delete(&rc);
|
(void)Delete(&rc);
|
||||||
|
|
||||||
p_internal->Free();
|
m_internal->Free();
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -616,7 +613,7 @@ wxThreadError wxThread::Delete(ExitCode *pRc)
|
|||||||
if ( IsPaused() )
|
if ( IsPaused() )
|
||||||
Resume();
|
Resume();
|
||||||
|
|
||||||
HANDLE hThread = p_internal->GetHandle();
|
HANDLE hThread = m_internal->GetHandle();
|
||||||
|
|
||||||
if ( IsRunning() )
|
if ( IsRunning() )
|
||||||
{
|
{
|
||||||
@@ -634,7 +631,7 @@ wxThreadError wxThread::Delete(ExitCode *pRc)
|
|||||||
{
|
{
|
||||||
wxCriticalSectionLocker lock(m_critsect);
|
wxCriticalSectionLocker lock(m_critsect);
|
||||||
|
|
||||||
p_internal->Cancel();
|
m_internal->Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if wxUSE_GUI
|
#if wxUSE_GUI
|
||||||
@@ -742,14 +739,14 @@ wxThreadError wxThread::Kill()
|
|||||||
if ( !IsRunning() )
|
if ( !IsRunning() )
|
||||||
return wxTHREAD_NOT_RUNNING;
|
return wxTHREAD_NOT_RUNNING;
|
||||||
|
|
||||||
if ( !::TerminateThread(p_internal->GetHandle(), (DWORD)-1) )
|
if ( !::TerminateThread(m_internal->GetHandle(), (DWORD)-1) )
|
||||||
{
|
{
|
||||||
wxLogSysError(_("Couldn't terminate thread"));
|
wxLogSysError(_("Couldn't terminate thread"));
|
||||||
|
|
||||||
return wxTHREAD_MISC_ERROR;
|
return wxTHREAD_MISC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
p_internal->Free();
|
m_internal->Free();
|
||||||
|
|
||||||
if ( IsDetached() )
|
if ( IsDetached() )
|
||||||
{
|
{
|
||||||
@@ -761,7 +758,7 @@ wxThreadError wxThread::Kill()
|
|||||||
|
|
||||||
void wxThread::Exit(ExitCode status)
|
void wxThread::Exit(ExitCode status)
|
||||||
{
|
{
|
||||||
p_internal->Free();
|
m_internal->Free();
|
||||||
|
|
||||||
if ( IsDetached() )
|
if ( IsDetached() )
|
||||||
{
|
{
|
||||||
@@ -784,50 +781,50 @@ void wxThread::SetPriority(unsigned int prio)
|
|||||||
{
|
{
|
||||||
wxCriticalSectionLocker lock(m_critsect);
|
wxCriticalSectionLocker lock(m_critsect);
|
||||||
|
|
||||||
p_internal->SetPriority(prio);
|
m_internal->SetPriority(prio);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int wxThread::GetPriority() const
|
unsigned int wxThread::GetPriority() const
|
||||||
{
|
{
|
||||||
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
|
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
|
||||||
|
|
||||||
return p_internal->GetPriority();
|
return m_internal->GetPriority();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long wxThread::GetId() const
|
unsigned long wxThread::GetId() const
|
||||||
{
|
{
|
||||||
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
|
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
|
||||||
|
|
||||||
return (unsigned long)p_internal->GetId();
|
return (unsigned long)m_internal->GetId();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxThread::IsRunning() const
|
bool wxThread::IsRunning() const
|
||||||
{
|
{
|
||||||
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
|
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
|
||||||
|
|
||||||
return p_internal->GetState() == STATE_RUNNING;
|
return m_internal->GetState() == STATE_RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxThread::IsAlive() const
|
bool wxThread::IsAlive() const
|
||||||
{
|
{
|
||||||
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
|
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
|
||||||
|
|
||||||
return (p_internal->GetState() == STATE_RUNNING) ||
|
return (m_internal->GetState() == STATE_RUNNING) ||
|
||||||
(p_internal->GetState() == STATE_PAUSED);
|
(m_internal->GetState() == STATE_PAUSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxThread::IsPaused() const
|
bool wxThread::IsPaused() const
|
||||||
{
|
{
|
||||||
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
|
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
|
||||||
|
|
||||||
return p_internal->GetState() == STATE_PAUSED;
|
return m_internal->GetState() == STATE_PAUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxThread::TestDestroy()
|
bool wxThread::TestDestroy()
|
||||||
{
|
{
|
||||||
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
|
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
|
||||||
|
|
||||||
return p_internal->GetState() == STATE_CANCELED;
|
return m_internal->GetState() == STATE_CANCELED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user