384a14ff32
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@62778 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1702 lines
58 KiB
Objective-C
1702 lines
58 KiB
Objective-C
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: thread.h
|
|
// Purpose: interface of all thread-related wxWidgets classes
|
|
// Author: wxWidgets team
|
|
// RCS-ID: $Id$
|
|
// Licence: wxWindows license
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/** See wxCondition. */
|
|
enum wxCondError
|
|
{
|
|
wxCOND_NO_ERROR = 0,
|
|
wxCOND_INVALID,
|
|
wxCOND_TIMEOUT, //!< WaitTimeout() has timed out
|
|
wxCOND_MISC_ERROR
|
|
};
|
|
|
|
|
|
/**
|
|
@class wxCondition
|
|
|
|
wxCondition variables correspond to pthread conditions or to Win32 event objects.
|
|
They may be used in a multithreaded application to wait until the given condition
|
|
becomes @true which happens when the condition becomes signaled.
|
|
|
|
For example, if a worker thread is doing some long task and another thread has
|
|
to wait until it is finished, the latter thread will wait on the condition
|
|
object and the worker thread will signal it on exit (this example is not
|
|
perfect because in this particular case it would be much better to just
|
|
wxThread::Wait for the worker thread, but if there are several worker threads
|
|
it already makes much more sense).
|
|
|
|
Note that a call to wxCondition::Signal may happen before the other thread calls
|
|
wxCondition::Wait and, just as with the pthread conditions, the signal is then
|
|
lost and so if you want to be sure that you don't miss it you must keep the
|
|
mutex associated with the condition initially locked and lock it again before calling
|
|
wxCondition::Signal. Of course, this means that this call is going to block
|
|
until wxCondition::Wait is called by another thread.
|
|
|
|
@section condition_example Example
|
|
|
|
This example shows how a main thread may launch a worker thread which starts
|
|
running and then waits until the main thread signals it to continue:
|
|
|
|
@code
|
|
class MySignallingThread : public wxThread
|
|
{
|
|
public:
|
|
MySignallingThread(wxMutex *mutex, wxCondition *condition)
|
|
{
|
|
m_mutex = mutex;
|
|
m_condition = condition;
|
|
|
|
Create();
|
|
}
|
|
|
|
virtual ExitCode Entry()
|
|
{
|
|
... do our job ...
|
|
|
|
// tell the other(s) thread(s) that we're about to terminate: we must
|
|
// lock the mutex first or we might signal the condition before the
|
|
// waiting threads start waiting on it!
|
|
wxMutexLocker lock(*m_mutex);
|
|
m_condition->Broadcast(); // same as Signal() here -- one waiter only
|
|
|
|
return 0;
|
|
}
|
|
|
|
private:
|
|
wxCondition *m_condition;
|
|
wxMutex *m_mutex;
|
|
};
|
|
|
|
int main()
|
|
{
|
|
wxMutex mutex;
|
|
wxCondition condition(mutex);
|
|
|
|
// the mutex should be initially locked
|
|
mutex.Lock();
|
|
|
|
// create and run the thread but notice that it won't be able to
|
|
// exit (and signal its exit) before we unlock the mutex below
|
|
MySignallingThread *thread = new MySignallingThread(&mutex, &condition);
|
|
|
|
thread->Run();
|
|
|
|
// wait for the thread termination: Wait() atomically unlocks the mutex
|
|
// which allows the thread to continue and starts waiting
|
|
condition.Wait();
|
|
|
|
// now we can exit
|
|
return 0;
|
|
}
|
|
@endcode
|
|
|
|
Of course, here it would be much better to simply use a joinable thread and
|
|
call wxThread::Wait on it, but this example does illustrate the importance of
|
|
properly locking the mutex when using wxCondition.
|
|
|
|
@library{wxbase}
|
|
@category{threading}
|
|
|
|
@see wxThread, wxMutex
|
|
*/
|
|
class wxCondition
|
|
{
|
|
public:
|
|
/**
|
|
Default and only constructor.
|
|
The @a mutex must be locked by the caller before calling Wait() function.
|
|
Use IsOk() to check if the object was successfully initialized.
|
|
*/
|
|
wxCondition(wxMutex& mutex);
|
|
|
|
/**
|
|
Destroys the wxCondition object.
|
|
|
|
The destructor is not virtual so this class should not be used polymorphically.
|
|
*/
|
|
~wxCondition();
|
|
|
|
/**
|
|
Broadcasts to all waiting threads, waking all of them up.
|
|
|
|
Note that this method may be called whether the mutex associated with
|
|
this condition is locked or not.
|
|
|
|
@see Signal()
|
|
*/
|
|
wxCondError Broadcast();
|
|
|
|
/**
|
|
Returns @true if the object had been initialized successfully, @false
|
|
if an error occurred.
|
|
*/
|
|
bool IsOk() const;
|
|
|
|
/**
|
|
Signals the object waking up at most one thread.
|
|
|
|
If several threads are waiting on the same condition, the exact thread
|
|
which is woken up is undefined. If no threads are waiting, the signal is
|
|
lost and the condition would have to be signalled again to wake up any
|
|
thread which may start waiting on it later.
|
|
|
|
Note that this method may be called whether the mutex associated with this
|
|
condition is locked or not.
|
|
|
|
@see Broadcast()
|
|
*/
|
|
wxCondError Signal();
|
|
|
|
/**
|
|
Waits until the condition is signalled.
|
|
|
|
This method atomically releases the lock on the mutex associated with this
|
|
condition (this is why it must be locked prior to calling Wait()) and puts the
|
|
thread to sleep until Signal() or Broadcast() is called.
|
|
It then locks the mutex again and returns.
|
|
|
|
Note that even if Signal() had been called before Wait() without waking
|
|
up any thread, the thread would still wait for another one and so it is
|
|
important to ensure that the condition will be signalled after
|
|
Wait() or the thread may sleep forever.
|
|
|
|
@return Returns wxCOND_NO_ERROR on success, another value if an error occurred.
|
|
|
|
@see WaitTimeout()
|
|
*/
|
|
wxCondError Wait();
|
|
|
|
/**
|
|
Waits until the condition is signalled or the timeout has elapsed.
|
|
|
|
This method is identical to Wait() except that it returns, with the
|
|
return code of @c wxCOND_TIMEOUT as soon as the given timeout expires.
|
|
|
|
@param milliseconds
|
|
Timeout in milliseconds
|
|
|
|
@return Returns wxCOND_NO_ERROR if the condition was signalled,
|
|
wxCOND_TIMEOUT if the timeout elapsed before this happened or
|
|
another error code from wxCondError enum.
|
|
*/
|
|
wxCondError WaitTimeout(unsigned long milliseconds);
|
|
};
|
|
|
|
|
|
/**
|
|
@class wxCriticalSectionLocker
|
|
|
|
This is a small helper class to be used with wxCriticalSection objects.
|
|
|
|
A wxCriticalSectionLocker enters the critical section in the constructor and
|
|
leaves it in the destructor making it much more difficult to forget to leave
|
|
a critical section (which, in general, will lead to serious and difficult
|
|
to debug problems).
|
|
|
|
Example of using it:
|
|
|
|
@code
|
|
void Set Foo()
|
|
{
|
|
// gs_critSect is some (global) critical section guarding access to the
|
|
// object "foo"
|
|
wxCriticalSectionLocker locker(gs_critSect);
|
|
|
|
if ( ... )
|
|
{
|
|
// do something
|
|
...
|
|
|
|
return;
|
|
}
|
|
|
|
// do something else
|
|
...
|
|
|
|
return;
|
|
}
|
|
@endcode
|
|
|
|
Without wxCriticalSectionLocker, you would need to remember to manually leave
|
|
the critical section before each @c return.
|
|
|
|
@library{wxbase}
|
|
@category{threading}
|
|
|
|
@see wxCriticalSection, wxMutexLocker
|
|
*/
|
|
class wxCriticalSectionLocker
|
|
{
|
|
public:
|
|
/**
|
|
Constructs a wxCriticalSectionLocker object associated with given
|
|
@a criticalsection and enters it.
|
|
*/
|
|
wxCriticalSectionLocker(wxCriticalSection& criticalsection);
|
|
|
|
/**
|
|
Destructor leaves the critical section.
|
|
*/
|
|
~wxCriticalSectionLocker();
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
@class wxThreadHelper
|
|
|
|
The wxThreadHelper class is a mix-in class that manages a single background
|
|
thread, either detached or joinable (see wxThread for the differences).
|
|
By deriving from wxThreadHelper, a class can implement the thread
|
|
code in its own wxThreadHelper::Entry() method and easily share data and
|
|
synchronization objects between the main thread and the worker thread.
|
|
|
|
Doing this prevents the awkward passing of pointers that is needed when the
|
|
original object in the main thread needs to synchronize with its worker thread
|
|
in its own wxThread derived object.
|
|
|
|
For example, wxFrame may need to make some calculations in a background thread
|
|
and then display the results of those calculations in the main window.
|
|
|
|
Ordinarily, a wxThread derived object would be created with the calculation
|
|
code implemented in wxThread::Entry. To access the inputs to the calculation,
|
|
the frame object would often need to pass a pointer to itself to the thread object.
|
|
Similarly, the frame object would hold a pointer to the thread object.
|
|
|
|
Shared data and synchronization objects could be stored in either object
|
|
though the object without the data would have to access the data through
|
|
a pointer.
|
|
However with wxThreadHelper the frame object and the thread object are
|
|
treated as the same object. Shared data and synchronization variables are
|
|
stored in the single object, eliminating a layer of indirection and the
|
|
associated pointers.
|
|
|
|
Example:
|
|
@code
|
|
wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);
|
|
|
|
class MyFrame : public wxFrame, public wxThreadHelper
|
|
{
|
|
public:
|
|
MyFrame(...) { ... }
|
|
~MyFrame()
|
|
{
|
|
// it's better to do any thread cleanup in the OnClose()
|
|
// event handler, rather than in the destructor.
|
|
// This is because the event loop for a top-level window is not
|
|
// active anymore when its destructor is called and if the thread
|
|
// sends events when ending, they won't be processed unless
|
|
// you ended the thread from OnClose.
|
|
// See @ref overview_windowdeletion for more info.
|
|
}
|
|
|
|
...
|
|
void DoStartALongTask();
|
|
void OnThreadUpdate(wxThreadEvent& evt);
|
|
void OnClose(wxCloseEvent& evt);
|
|
...
|
|
|
|
protected:
|
|
virtual wxThread::ExitCode Entry();
|
|
|
|
// the output data of the Entry() routine:
|
|
char m_data[1024];
|
|
wxCriticalSection m_dataCS; // protects field above
|
|
|
|
DECLARE_EVENT_TABLE()
|
|
};
|
|
|
|
wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent)
|
|
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
|
|
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_UPDATE, MyFrame::OnThreadUpdate)
|
|
EVT_CLOSE(MyFrame::OnClose)
|
|
END_EVENT_TABLE()
|
|
|
|
void MyFrame::DoStartALongTask()
|
|
{
|
|
// we want to start a long task, but we don't want our GUI to block
|
|
// while it's executed, so we use a thread to do it.
|
|
if (CreateThread(wxTHREAD_JOINABLE) != wxTHREAD_NO_ERROR)
|
|
{
|
|
wxLogError("Could not create the worker thread!");
|
|
return;
|
|
}
|
|
|
|
// go!
|
|
if (GetThread()->Run() != wxTHREAD_NO_ERROR)
|
|
{
|
|
wxLogError("Could not run the worker thread!");
|
|
return;
|
|
}
|
|
}
|
|
|
|
wxThread::ExitCode MyFrame::Entry()
|
|
{
|
|
// IMPORTANT:
|
|
// this function gets executed in the secondary thread context!
|
|
|
|
int offset = 0;
|
|
|
|
// here we do our long task, periodically calling TestDestroy():
|
|
while (!GetThread()->TestDestroy())
|
|
{
|
|
// since this Entry() is implemented in MyFrame context we don't
|
|
// need any pointer to access the m_data, m_processedData, m_dataCS
|
|
// variables... very nice!
|
|
|
|
// this is an example of the generic structure of a download thread:
|
|
char buffer[1024];
|
|
download_chunk(buffer, 1024); // this takes time...
|
|
|
|
{
|
|
// ensure noone reads m_data while we write it
|
|
wxCriticalSectionLocker lock(m_dataCS);
|
|
memcpy(m_data+offset, buffer, 1024);
|
|
offset += 1024;
|
|
}
|
|
|
|
|
|
// VERY IMPORTANT: do not call any GUI function inside this
|
|
// function; rather use wxQueueEvent():
|
|
wxQueueEvent(this, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));
|
|
// we used pointer 'this' assuming it's safe; see OnClose()
|
|
}
|
|
|
|
// TestDestroy() returned true (which means the main thread asked us
|
|
// to terminate as soon as possible) or we ended the long task...
|
|
return (wxThread::ExitCode)0;
|
|
}
|
|
|
|
void MyFrame::OnClose(wxCloseEvent&)
|
|
{
|
|
// important: before terminating, we _must_ wait for our joinable
|
|
// thread to end, if it's running; in fact it uses variables of this
|
|
// instance and posts events to *this event handler
|
|
|
|
if (GetThread() && // DoStartALongTask() may have not been called
|
|
GetThread()->IsRunning())
|
|
GetThread()->Wait();
|
|
|
|
Destroy();
|
|
}
|
|
|
|
void MyFrame::OnThreadUpdate(wxThreadEvent& evt)
|
|
{
|
|
// ...do something... e.g. m_pGauge->Pulse();
|
|
|
|
// read some parts of m_data just for fun:
|
|
wxCriticalSectionLocker lock(m_dataCS);
|
|
wxPrintf("%c", m_data[100]);
|
|
}
|
|
@endcode
|
|
|
|
@library{wxbase}
|
|
@category{threading}
|
|
|
|
@see wxThread, wxThreadEvent
|
|
*/
|
|
class wxThreadHelper
|
|
{
|
|
public:
|
|
/**
|
|
This constructor simply initializes internal member variables and tells
|
|
wxThreadHelper which type the thread internally managed should be.
|
|
*/
|
|
wxThreadHelper(wxThreadKind kind = wxTHREAD_JOINABLE);
|
|
|
|
/**
|
|
The destructor frees the resources associated with the thread, forcing
|
|
it to terminate (it uses wxThread::Kill function).
|
|
|
|
Because of the wxThread::Kill unsafety, you should always wait
|
|
(with wxThread::Wait) for joinable threads to end or call wxThread::Delete
|
|
on detached threads, instead of relying on this destructor for stopping
|
|
the thread.
|
|
*/
|
|
virtual ~wxThreadHelper();
|
|
|
|
/**
|
|
This is the entry point of the thread.
|
|
|
|
This function is pure virtual and must be implemented by any derived class.
|
|
The thread execution will start here.
|
|
|
|
You'll typically want your Entry() to look like:
|
|
@code
|
|
wxThread::ExitCode Entry()
|
|
{
|
|
while (!GetThread()->TestDestroy())
|
|
{
|
|
// ... do some work ...
|
|
|
|
if (IsWorkCompleted)
|
|
break;
|
|
|
|
if (HappenedStoppingError)
|
|
return (wxThread::ExitCode)1; // failure
|
|
}
|
|
|
|
return (wxThread::ExitCode)0; // success
|
|
}
|
|
@endcode
|
|
|
|
The returned value is the thread exit code which is only useful for
|
|
joinable threads and is the value returned by @c "GetThread()->Wait()".
|
|
|
|
This function is called by wxWidgets itself and should never be called
|
|
directly.
|
|
*/
|
|
virtual ExitCode Entry() = 0;
|
|
|
|
/**
|
|
@deprecated
|
|
Use CreateThread() instead.
|
|
*/
|
|
wxThreadError Create(unsigned int stackSize = 0);
|
|
|
|
/**
|
|
Creates a new thread of the given @a kind.
|
|
|
|
The thread object is created in the suspended state, and you
|
|
should call @ref wxThread::Run "GetThread()->Run()" to start running it.
|
|
|
|
You may optionally specify the stack size to be allocated to it (ignored
|
|
on platforms that don't support setting it explicitly, e.g. Unix).
|
|
|
|
@return One of the ::wxThreadError enum values.
|
|
*/
|
|
wxThreadError CreateThread(wxThreadKind kind = wxTHREAD_JOINABLE,
|
|
unsigned int stackSize = 0);
|
|
|
|
/**
|
|
This is a public function that returns the wxThread object associated with
|
|
the thread.
|
|
*/
|
|
wxThread* GetThread() const;
|
|
|
|
/**
|
|
Returns the last type of thread given to the CreateThread() function
|
|
or to the constructor.
|
|
*/
|
|
wxThreadKind GetThreadKind() const;
|
|
};
|
|
|
|
/**
|
|
Possible critical section types
|
|
*/
|
|
|
|
enum wxCriticalSectionType
|
|
{
|
|
wxCRITSEC_DEFAULT,
|
|
/** Recursive critical section under both Windows and Unix */
|
|
|
|
wxCRITSEC_NON_RECURSIVE
|
|
/** Non-recursive critical section under Unix, recursive under Windows */
|
|
};
|
|
|
|
/**
|
|
@class wxCriticalSection
|
|
|
|
A critical section object is used for exactly the same purpose as a wxMutex.
|
|
The only difference is that under Windows platform critical sections are only
|
|
visible inside one process, while mutexes may be shared among processes,
|
|
so using critical sections is slightly more efficient.
|
|
|
|
The terminology is also slightly different: mutex may be locked (or acquired)
|
|
and unlocked (or released) while critical section is entered and left by the program.
|
|
|
|
Finally, you should try to use wxCriticalSectionLocker class whenever
|
|
possible instead of directly using wxCriticalSection for the same reasons
|
|
wxMutexLocker is preferrable to wxMutex - please see wxMutex for an example.
|
|
|
|
@library{wxbase}
|
|
@category{threading}
|
|
|
|
@note Critical sections can be used before the wxWidgets library is fully
|
|
initialized. In particular, it's safe to create global
|
|
wxCriticalSection instances.
|
|
|
|
@see wxThread, wxCondition, wxCriticalSectionLocker
|
|
*/
|
|
class wxCriticalSection
|
|
{
|
|
public:
|
|
/**
|
|
Default constructor initializes critical section object.
|
|
By default critical sections are recursive under Unix and Windows.
|
|
*/
|
|
wxCriticalSection( wxCriticalSectionType critSecType = wxCRITSEC_DEFAULT );
|
|
|
|
/**
|
|
Destructor frees the resources.
|
|
*/
|
|
~wxCriticalSection();
|
|
|
|
/**
|
|
Enter the critical section (same as locking a mutex): if another thread
|
|
has already entered it, this call will block until the other thread
|
|
calls Leave().
|
|
There is no error return for this function.
|
|
|
|
After entering the critical section protecting a data variable,
|
|
the thread running inside the critical section may safely use/modify it.
|
|
|
|
Note that entering the same critical section twice or more from the same
|
|
thread doesn't result in a deadlock; in this case in fact this function will
|
|
immediately return.
|
|
*/
|
|
void Enter();
|
|
|
|
/**
|
|
Leave the critical section allowing other threads use the global data
|
|
protected by it. There is no error return for this function.
|
|
*/
|
|
void Leave();
|
|
};
|
|
|
|
/**
|
|
The possible thread kinds.
|
|
*/
|
|
enum wxThreadKind
|
|
{
|
|
/** Detached thread */
|
|
wxTHREAD_DETACHED,
|
|
|
|
/** Joinable thread */
|
|
wxTHREAD_JOINABLE
|
|
};
|
|
|
|
/**
|
|
The possible thread errors.
|
|
*/
|
|
enum wxThreadError
|
|
{
|
|
/** No error */
|
|
wxTHREAD_NO_ERROR = 0,
|
|
|
|
/** No resource left to create a new thread. */
|
|
wxTHREAD_NO_RESOURCE,
|
|
|
|
/** The thread is already running. */
|
|
wxTHREAD_RUNNING,
|
|
|
|
/** The thread isn't running. */
|
|
wxTHREAD_NOT_RUNNING,
|
|
|
|
/** Thread we waited for had to be killed. */
|
|
wxTHREAD_KILLED,
|
|
|
|
/** Some other error */
|
|
wxTHREAD_MISC_ERROR
|
|
};
|
|
|
|
/**
|
|
Defines the interval of priority
|
|
*/
|
|
enum
|
|
{
|
|
WXTHREAD_MIN_PRIORITY = 0u,
|
|
WXTHREAD_DEFAULT_PRIORITY = 50u,
|
|
WXTHREAD_MAX_PRIORITY = 100u
|
|
};
|
|
|
|
|
|
/**
|
|
@class wxThread
|
|
|
|
A thread is basically a path of execution through a program.
|
|
Threads are sometimes called @e light-weight processes, but the fundamental difference
|
|
between threads and processes is that memory spaces of different processes are
|
|
separated while all threads share the same address space.
|
|
|
|
While it makes it much easier to share common data between several threads, it
|
|
also makes it much easier to shoot oneself in the foot, so careful use of
|
|
synchronization objects such as mutexes (see wxMutex) or critical sections
|
|
(see wxCriticalSection) is recommended.
|
|
In addition, don't create global thread objects because they allocate memory
|
|
in their constructor, which will cause problems for the memory checking system.
|
|
|
|
|
|
@section thread_types Types of wxThreads
|
|
|
|
There are two types of threads in wxWidgets: @e detached and @e joinable,
|
|
modeled after the the POSIX thread API. This is different from the Win32 API
|
|
where all threads are joinable.
|
|
|
|
By default wxThreads in wxWidgets use the @b detached behavior.
|
|
Detached threads delete themselves once they have completed, either by themselves
|
|
when they complete processing or through a call to Delete(), and thus
|
|
@b must be created on the heap (through the new operator, for example).
|
|
|
|
Typically you'll want to store the instances of the detached wxThreads you
|
|
allocate, so that you can call functions on them.
|
|
Because of their nature however you'll need to always use a critical section
|
|
when accessing them:
|
|
|
|
@code
|
|
// declare a new type of event, to be used by our MyThread class:
|
|
wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent);
|
|
wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);
|
|
class MyFrame;
|
|
|
|
class MyThread : public wxThread
|
|
{
|
|
public:
|
|
MyThread(MyFrame *handler)
|
|
: wxThread(wxTHREAD_DETACHED)
|
|
{ m_pHandler = handler }
|
|
~MyThread();
|
|
|
|
protected:
|
|
virtual ExitCode Entry();
|
|
MyFrame *m_pHandler;
|
|
};
|
|
|
|
class MyFrame : public wxFrame
|
|
{
|
|
public:
|
|
...
|
|
~MyFrame()
|
|
{
|
|
// it's better to do any thread cleanup in the OnClose()
|
|
// event handler, rather than in the destructor.
|
|
// This is because the event loop for a top-level window is not
|
|
// active anymore when its destructor is called and if the thread
|
|
// sends events when ending, they won't be processed unless
|
|
// you ended the thread from OnClose.
|
|
// See @ref overview_windowdeletion for more info.
|
|
}
|
|
...
|
|
void DoStartThread();
|
|
void DoPauseThread();
|
|
|
|
// a resume routine would be nearly identic to DoPauseThread()
|
|
void DoResumeThread() { ... }
|
|
|
|
void OnThreadUpdate(wxThreadEvent&);
|
|
void OnThreadCompletion(wxThreadEvent&);
|
|
void OnClose(wxCloseEvent&);
|
|
|
|
protected:
|
|
MyThread *m_pThread;
|
|
wxCriticalSection m_pThreadCS; // protects the m_pThread pointer
|
|
|
|
DECLARE_EVENT_TABLE()
|
|
};
|
|
|
|
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
|
|
EVT_CLOSE(MyFrame::OnClose)
|
|
EVT_MENU(Minimal_Start, MyFrame::DoStartThread)
|
|
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_UPDATE, MyFrame::OnThreadUpdate)
|
|
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_MYTHREAD_COMPLETED, MyFrame::OnThreadCompletion)
|
|
END_EVENT_TABLE()
|
|
|
|
wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent)
|
|
wxDEFINE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent)
|
|
|
|
void MyFrame::DoStartThread()
|
|
{
|
|
m_pThread = new MyThread(this);
|
|
|
|
if ( m_pThread->Create() != wxTHREAD_NO_ERROR )
|
|
{
|
|
wxLogError("Can't create the thread!");
|
|
delete m_pThread;
|
|
m_pThread = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (m_pThread->Run() != wxTHREAD_NO_ERROR )
|
|
{
|
|
wxLogError("Can't create the thread!");
|
|
delete m_pThread;
|
|
m_pThread = NULL;
|
|
}
|
|
|
|
// after the call to wxThread::Run(), the m_pThread pointer is "unsafe":
|
|
// at any moment the thread may cease to exist (because it completes its work).
|
|
// To avoid dangling pointers OnThreadExit() will set m_pThread
|
|
// to NULL when the thread dies.
|
|
}
|
|
}
|
|
|
|
wxThread::ExitCode MyThread::Entry()
|
|
{
|
|
while (!TestDestroy())
|
|
{
|
|
// ... do a bit of work...
|
|
|
|
wxQueueEvent(m_pHandler, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_UPDATE));
|
|
}
|
|
|
|
// signal the event handler that this thread is going to be destroyed
|
|
// NOTE: here we assume that using the m_pHandler pointer is safe,
|
|
// (in this case this is assured by the MyFrame destructor)
|
|
wxQueueEvent(m_pHandler, new wxThreadEvent(wxEVT_COMMAND_MYTHREAD_COMPLETED));
|
|
|
|
return (wxThread::ExitCode)0; // success
|
|
}
|
|
|
|
MyThread::~MyThread()
|
|
{
|
|
wxCriticalSectionLocker enter(m_pHandler->m_pThreadCS);
|
|
|
|
// the thread is being destroyed; make sure not to leave dangling pointers around
|
|
m_pHandler->m_pThread = NULL;
|
|
}
|
|
|
|
void MyFrame::OnThreadCompletion(wxThreadEvent&)
|
|
{
|
|
wxMessageOutputDebug().Printf("MYFRAME: MyThread exited!\n");
|
|
}
|
|
|
|
void MyFrame::OnThreadUpdate(wxThreadEvent&)
|
|
{
|
|
wxMessageOutputDebug().Printf("MYFRAME: MyThread update...\n");
|
|
}
|
|
|
|
void MyFrame::DoPauseThread()
|
|
{
|
|
// anytime we access the m_pThread pointer we must ensure that it won't
|
|
// be modified in the meanwhile; since only a single thread may be
|
|
// inside a given critical section at a given time, the following code
|
|
// is safe:
|
|
wxCriticalSectionLocker enter(m_pThreadCS);
|
|
|
|
if (m_pThread) // does the thread still exist?
|
|
{
|
|
// without a critical section, once reached this point it may happen
|
|
// that the OS scheduler gives control to the MyThread::Entry() function,
|
|
// which in turn may return (because it completes its work) making
|
|
// invalid the m_pThread pointer
|
|
|
|
if (m_pThread->Pause() != wxTHREAD_NO_ERROR )
|
|
wxLogError("Can't pause the thread!");
|
|
}
|
|
}
|
|
|
|
void MyFrame::OnClose(wxCloseEvent&)
|
|
{
|
|
{
|
|
wxCriticalSectionLocker enter(m_pThreadCS);
|
|
|
|
if (m_pThread) // does the thread still exist?
|
|
{
|
|
m_out.Printf("MYFRAME: deleting thread");
|
|
|
|
if (m_pThread->Delete() != wxTHREAD_NO_ERROR )
|
|
wxLogError("Can't delete the thread!");
|
|
}
|
|
} // exit from the critical section to give the thread
|
|
// the possibility to enter its destructor
|
|
// (which is guarded with m_pThreadCS critical section!)
|
|
|
|
while (1)
|
|
{
|
|
{ // was the ~MyThread() function executed?
|
|
wxCriticalSectionLocker enter(m_pThreadCS);
|
|
if (!m_pThread) break;
|
|
}
|
|
|
|
// wait for thread completion
|
|
wxThread::This()->Sleep(1);
|
|
}
|
|
|
|
Destroy();
|
|
}
|
|
@endcode
|
|
|
|
For a more detailed and comprehensive example, see @sample{thread}.
|
|
For a simpler way to share data and synchronization objects between
|
|
the main and the secondary thread see wxThreadHelper.
|
|
|
|
Conversely, @b joinable threads do not delete themselves when they are done
|
|
processing and as such are safe to create on the stack. Joinable threads
|
|
also provide the ability for one to get value it returned from Entry()
|
|
through Wait().
|
|
You shouldn't hurry to create all the threads joinable, however, because this
|
|
has a disadvantage as well: you @b must Wait() for a joinable thread or the
|
|
system resources used by it will never be freed, and you also must delete the
|
|
corresponding wxThread object yourself if you did not create it on the stack.
|
|
In contrast, detached threads are of the "fire-and-forget" kind: you only have
|
|
to start a detached thread and it will terminate and destroy itself.
|
|
|
|
|
|
@section thread_deletion wxThread Deletion
|
|
|
|
Regardless of whether it has terminated or not, you should call Wait() on a
|
|
@b joinable thread to release its memory, as outlined in @ref thread_types.
|
|
If you created a joinable thread on the heap, remember to delete it manually
|
|
with the @c delete operator or similar means as only detached threads handle
|
|
this type of memory management.
|
|
|
|
Since @b detached threads delete themselves when they are finished processing,
|
|
you should take care when calling a routine on one. If you are certain the
|
|
thread is still running and would like to end it, you may call Delete()
|
|
to gracefully end it (which implies that the thread will be deleted after
|
|
that call to Delete()). It should be implied that you should @b never attempt
|
|
to delete a detached thread with the @c delete operator or similar means.
|
|
|
|
As mentioned, Wait() or Delete() functions attempt to gracefully terminate a
|
|
joinable and a detached thread, respectively. They do this by waiting until
|
|
the thread in question calls TestDestroy() or ends processing (i.e. returns
|
|
from wxThread::Entry).
|
|
|
|
Obviously, if the thread does call TestDestroy() and does not end, the
|
|
thread which called Wait() or Delete() will come to halt.
|
|
This is why it's important to call TestDestroy() in the Entry() routine of
|
|
your threads as often as possible and immediately exit when it returns @true.
|
|
|
|
As a last resort you can end the thread immediately through Kill(). It is
|
|
strongly recommended that you do not do this, however, as it does not free
|
|
the resources associated with the object (although the wxThread object of
|
|
detached threads will still be deleted) and could leave the C runtime
|
|
library in an undefined state.
|
|
|
|
|
|
@section thread_secondary wxWidgets Calls in Secondary Threads
|
|
|
|
All threads other than the "main application thread" (the one running
|
|
wxApp::OnInit() or the one your main function runs in, for example) are
|
|
considered "secondary threads". These include all threads created by Create()
|
|
or the corresponding constructors.
|
|
|
|
GUI calls, such as those to a wxWindow or wxBitmap are explicitly not safe
|
|
at all in secondary threads and could end your application prematurely.
|
|
This is due to several reasons, including the underlying native API and
|
|
the fact that wxThread does not run a GUI event loop similar to other APIs
|
|
as MFC.
|
|
|
|
A workaround for some wxWidgets ports is calling wxMutexGUIEnter()
|
|
before any GUI calls and then calling wxMutexGUILeave() afterwords.
|
|
However, the recommended way is to simply process the GUI calls in the main
|
|
thread through an event that is posted by wxQueueEvent().
|
|
This does not imply that calls to these classes are thread-safe, however,
|
|
as most wxWidgets classes are not thread-safe, including wxString.
|
|
|
|
|
|
@section thread_poll Don't Poll a wxThread
|
|
|
|
A common problem users experience with wxThread is that in their main thread
|
|
they will check the thread every now and then to see if it has ended through
|
|
IsRunning(), only to find that their application has run into problems
|
|
because the thread is using the default behavior (i.e. it's @b detached) and
|
|
has already deleted itself.
|
|
Naturally, they instead attempt to use joinable threads in place of the previous
|
|
behavior. However, polling a wxThread for when it has ended is in general a
|
|
bad idea - in fact calling a routine on any running wxThread should be avoided
|
|
if possible. Instead, find a way to notify yourself when the thread has ended.
|
|
|
|
Usually you only need to notify the main thread, in which case you can
|
|
post an event to it via wxQueueEvent().
|
|
In the case of secondary threads you can call a routine of another class
|
|
when the thread is about to complete processing and/or set the value of
|
|
a variable, possibly using mutexes (see wxMutex) and/or other synchronization
|
|
means if necessary.
|
|
|
|
@library{wxbase}
|
|
@category{threading}
|
|
|
|
@see wxThreadHelper, wxMutex, wxCondition, wxCriticalSection,
|
|
@ref overview_thread
|
|
*/
|
|
class wxThread
|
|
{
|
|
public:
|
|
/**
|
|
The return type for the thread functions.
|
|
*/
|
|
typedef void* ExitCode;
|
|
|
|
/**
|
|
This constructor creates a new detached (default) or joinable C++
|
|
thread object. It does not create or start execution of the real thread -
|
|
for this you should use the Create() and Run() methods.
|
|
|
|
The possible values for @a kind parameters are:
|
|
- @b wxTHREAD_DETACHED - Creates a detached thread.
|
|
- @b wxTHREAD_JOINABLE - Creates a joinable thread.
|
|
*/
|
|
wxThread(wxThreadKind kind = wxTHREAD_DETACHED);
|
|
|
|
/**
|
|
The destructor frees the resources associated with the thread.
|
|
Notice that you should never delete a detached thread -- you may only call
|
|
Delete() on it or wait until it terminates (and auto destructs) itself.
|
|
|
|
Because the detached threads delete themselves, they can only be allocated on the heap.
|
|
Joinable threads should be deleted explicitly. The Delete() and Kill() functions
|
|
will not delete the C++ thread object. It is also safe to allocate them on stack.
|
|
*/
|
|
virtual ~wxThread();
|
|
|
|
/**
|
|
Creates a new thread.
|
|
|
|
The thread object is created in the suspended state, and you should call Run()
|
|
to start running it. You may optionally specify the stack size to be allocated
|
|
to it (Ignored on platforms that don't support setting it explicitly,
|
|
eg. Unix system without @c pthread_attr_setstacksize).
|
|
|
|
If you do not specify the stack size,the system's default value is used.
|
|
|
|
@warning
|
|
It is a good idea to explicitly specify a value as systems'
|
|
default values vary from just a couple of KB on some systems (BSD and
|
|
OS/2 systems) to one or several MB (Windows, Solaris, Linux).
|
|
So, if you have a thread that requires more than just a few KB of memory, you
|
|
will have mysterious problems on some platforms but not on the common ones.
|
|
On the other hand, just indicating a large stack size by default will give you
|
|
performance issues on those systems with small default stack since those
|
|
typically use fully committed memory for the stack.
|
|
On the contrary, if you use a lot of threads (say several hundred),
|
|
virtual adress space can get tight unless you explicitly specify a
|
|
smaller amount of thread stack space for each thread.
|
|
|
|
@return One of:
|
|
- @b wxTHREAD_NO_ERROR - No error.
|
|
- @b wxTHREAD_NO_RESOURCE - There were insufficient resources to create the thread.
|
|
- @b wxTHREAD_NO_RUNNING - The thread is already running
|
|
*/
|
|
wxThreadError Create(unsigned int stackSize = 0);
|
|
|
|
/**
|
|
Calling Delete() gracefully terminates a @b detached thread, either when
|
|
the thread calls TestDestroy() or when it finishes processing.
|
|
|
|
@note
|
|
This function works on a joinable thread but in that case makes
|
|
the TestDestroy() function of the thread return @true and then
|
|
waits for its completion (i.e. it differs from Wait() because
|
|
it asks the thread to terminate before waiting).
|
|
|
|
See @ref thread_deletion for a broader explanation of this routine.
|
|
*/
|
|
wxThreadError Delete(void** rc = NULL);
|
|
|
|
/**
|
|
Returns the number of system CPUs or -1 if the value is unknown.
|
|
|
|
For multi-core systems the returned value is typically the total number
|
|
of @e cores, since the OS usually abstract a single N-core CPU
|
|
as N different cores.
|
|
|
|
@see SetConcurrency()
|
|
*/
|
|
static int GetCPUCount();
|
|
|
|
/**
|
|
Returns the platform specific thread ID of the current thread as a long.
|
|
|
|
This can be used to uniquely identify threads, even if they are not wxThreads.
|
|
|
|
@see GetMainId()
|
|
*/
|
|
static wxThreadIdType GetCurrentId();
|
|
|
|
/**
|
|
Gets the thread identifier: this is a platform dependent number that uniquely
|
|
identifies the thread throughout the system during its existence
|
|
(i.e. the thread identifiers may be reused).
|
|
*/
|
|
wxThreadIdType GetId() const;
|
|
|
|
/**
|
|
Returns the thread kind as it was given in the ctor.
|
|
|
|
@since 2.9.0
|
|
*/
|
|
wxThreadKind GetKind() const;
|
|
|
|
/**
|
|
Returns the thread ID of the main thread.
|
|
|
|
@see IsMain()
|
|
|
|
@since 2.9.1
|
|
*/
|
|
static wxThreadIdType GetMainId();
|
|
|
|
/**
|
|
Gets the priority of the thread, between zero and 100.
|
|
|
|
The following priorities are defined:
|
|
- @b WXTHREAD_MIN_PRIORITY: 0
|
|
- @b WXTHREAD_DEFAULT_PRIORITY: 50
|
|
- @b WXTHREAD_MAX_PRIORITY: 100
|
|
*/
|
|
unsigned int GetPriority() const;
|
|
|
|
/**
|
|
Returns @true if the thread is alive (i.e. started and not terminating).
|
|
|
|
Note that this function can only safely be used with joinable threads, not
|
|
detached ones as the latter delete themselves and so when the real thread is
|
|
no longer alive, it is not possible to call this function because
|
|
the wxThread object no longer exists.
|
|
*/
|
|
bool IsAlive() const;
|
|
|
|
/**
|
|
Returns @true if the thread is of the detached kind, @false if it is a
|
|
joinable one.
|
|
*/
|
|
bool IsDetached() const;
|
|
|
|
/**
|
|
Returns @true if the calling thread is the main application thread.
|
|
|
|
Main thread in the context of wxWidgets is the one which initialized
|
|
the library.
|
|
|
|
@see GetMainId(), GetCurrentId()
|
|
*/
|
|
static bool IsMain();
|
|
|
|
/**
|
|
Returns @true if the thread is paused.
|
|
*/
|
|
bool IsPaused() const;
|
|
|
|
/**
|
|
Returns @true if the thread is running.
|
|
|
|
This method may only be safely used for joinable threads, see the remark in
|
|
IsAlive().
|
|
*/
|
|
bool IsRunning() const;
|
|
|
|
/**
|
|
Immediately terminates the target thread.
|
|
|
|
@b "This function is dangerous and should be used with extreme care"
|
|
(and not used at all whenever possible)! The resources allocated to the
|
|
thread will not be freed and the state of the C runtime library may become
|
|
inconsistent. Use Delete() for detached threads or Wait() for joinable
|
|
threads instead.
|
|
|
|
For detached threads Kill() will also delete the associated C++ object.
|
|
However this will not happen for joinable threads and this means that you will
|
|
still have to delete the wxThread object yourself to avoid memory leaks.
|
|
|
|
In neither case OnExit() of the dying thread will be called, so no
|
|
thread-specific cleanup will be performed.
|
|
This function can only be called from another thread context, i.e. a thread
|
|
cannot kill itself.
|
|
|
|
It is also an error to call this function for a thread which is not running or
|
|
paused (in the latter case, the thread will be resumed first) -- if you do it,
|
|
a @b wxTHREAD_NOT_RUNNING error will be returned.
|
|
*/
|
|
wxThreadError Kill();
|
|
|
|
/**
|
|
Suspends the thread.
|
|
|
|
Under some implementations (Win32), the thread is suspended immediately,
|
|
under others it will only be suspended when it calls TestDestroy() for
|
|
the next time (hence, if the thread doesn't call it at all, it won't be
|
|
suspended).
|
|
|
|
This function can only be called from another thread context.
|
|
*/
|
|
wxThreadError Pause();
|
|
|
|
/**
|
|
Resumes a thread suspended by the call to Pause().
|
|
|
|
This function can only be called from another thread context.
|
|
*/
|
|
wxThreadError Resume();
|
|
|
|
/**
|
|
Starts the thread execution. Should be called after Create().
|
|
|
|
Note that once you Run() a @b detached thread, @e any function call you do
|
|
on the thread pointer (you must allocate it on the heap) is @e "unsafe";
|
|
i.e. the thread may have terminated at any moment after Run() and your pointer
|
|
may be dangling. See @ref thread_types for an example of safe manipulation
|
|
of detached threads.
|
|
|
|
This function can only be called from another thread context.
|
|
*/
|
|
wxThreadError Run();
|
|
|
|
/**
|
|
Sets the thread concurrency level for this process.
|
|
|
|
This is, roughly, the number of threads that the system tries to schedule
|
|
to run in parallel.
|
|
The value of 0 for @a level may be used to set the default one.
|
|
|
|
@return @true on success or @false otherwise (for example, if this function is
|
|
not implemented for this platform -- currently everything except Solaris).
|
|
*/
|
|
static bool SetConcurrency(size_t level);
|
|
|
|
/**
|
|
Sets the priority of the thread, between 0 and 100.
|
|
It can only be set after calling Create() but before calling Run().
|
|
|
|
The following priorities are defined:
|
|
- @b WXTHREAD_MIN_PRIORITY: 0
|
|
- @b WXTHREAD_DEFAULT_PRIORITY: 50
|
|
- @b WXTHREAD_MAX_PRIORITY: 100
|
|
*/
|
|
void SetPriority(unsigned int priority);
|
|
|
|
/**
|
|
Pauses the thread execution for the given amount of time.
|
|
|
|
This is the same as wxMilliSleep().
|
|
*/
|
|
static void Sleep(unsigned long milliseconds);
|
|
|
|
/**
|
|
This function should be called periodically by the thread to ensure that
|
|
calls to Pause() and Delete() will work.
|
|
|
|
If it returns @true, the thread should exit as soon as possible.
|
|
Notice that under some platforms (POSIX), implementation of Pause() also
|
|
relies on this function being called, so not calling it would prevent
|
|
both stopping and suspending thread from working.
|
|
*/
|
|
virtual bool TestDestroy();
|
|
|
|
/**
|
|
Return the thread object for the calling thread.
|
|
|
|
@NULL is returned if the calling thread is the main (GUI) thread, but
|
|
IsMain() should be used to test whether the thread is really the main one
|
|
because @NULL may also be returned for the thread not created with wxThread
|
|
class. Generally speaking, the return value for such a thread is undefined.
|
|
*/
|
|
static wxThread* This();
|
|
|
|
/**
|
|
Waits for a @b joinable thread to terminate and returns the value the thread
|
|
returned from Entry() or @c "(ExitCode)-1" on error. Notice that, unlike
|
|
Delete(), this function doesn't cancel the thread in any way so the caller
|
|
waits for as long as it takes to the thread to exit.
|
|
|
|
You can only Wait() for @b joinable (not detached) threads.
|
|
|
|
This function can only be called from another thread context.
|
|
|
|
See @ref thread_deletion for a broader explanation of this routine.
|
|
*/
|
|
ExitCode Wait();
|
|
|
|
/**
|
|
Give the rest of the thread's time-slice to the system allowing the other
|
|
threads to run.
|
|
|
|
Note that using this function is @b strongly discouraged, since in
|
|
many cases it indicates a design weakness of your threading model
|
|
(as does using Sleep() functions).
|
|
|
|
Threads should use the CPU in an efficient manner, i.e. they should
|
|
do their current work efficiently, then as soon as the work is done block
|
|
on a wakeup event (wxCondition, wxMutex, select(), poll(), ...) which will
|
|
get signalled e.g. by other threads or a user device once further thread
|
|
work is available.
|
|
Using Yield() or Sleep() indicates polling-type behaviour, since we're
|
|
fuzzily giving up our timeslice and wait until sometime later we'll get
|
|
reactivated, at which time we realize that there isn't really much to do
|
|
and Yield() again...
|
|
|
|
The most critical characteristic of Yield() is that it's operating system
|
|
specific: there may be scheduler changes which cause your thread to not
|
|
wake up relatively soon again, but instead many seconds later,
|
|
causing huge performance issues for your application.
|
|
|
|
<strong>
|
|
With a well-behaving, CPU-efficient thread the operating system is likely
|
|
to properly care for its reactivation the moment it needs it, whereas with
|
|
non-deterministic, Yield-using threads all bets are off and the system
|
|
scheduler is free to penalize them drastically</strong>, and this effect
|
|
gets worse with increasing system load due to less free CPU resources available.
|
|
You may refer to various Linux kernel @c sched_yield discussions for more
|
|
information.
|
|
|
|
See also Sleep().
|
|
*/
|
|
static void Yield();
|
|
|
|
protected:
|
|
|
|
/**
|
|
This is the entry point of the thread.
|
|
|
|
This function is pure virtual and must be implemented by any derived class.
|
|
The thread execution will start here.
|
|
|
|
The returned value is the thread exit code which is only useful for
|
|
joinable threads and is the value returned by Wait().
|
|
This function is called by wxWidgets itself and should never be called
|
|
directly.
|
|
*/
|
|
virtual ExitCode Entry() = 0;
|
|
|
|
/**
|
|
This is a protected function of the wxThread class and thus can only be called
|
|
from a derived class. It also can only be called in the context of this
|
|
thread, i.e. a thread can only exit from itself, not from another thread.
|
|
|
|
This function will terminate the OS thread (i.e. stop the associated path of
|
|
execution) and also delete the associated C++ object for detached threads.
|
|
OnExit() will be called just before exiting.
|
|
*/
|
|
void Exit(ExitCode exitcode = 0);
|
|
|
|
private:
|
|
|
|
/**
|
|
Called when the thread exits.
|
|
|
|
This function is called in the context of the thread associated with the
|
|
wxThread object, not in the context of the main thread.
|
|
This function will not be called if the thread was @ref Kill() killed.
|
|
|
|
This function should never be called directly.
|
|
*/
|
|
virtual void OnExit();
|
|
};
|
|
|
|
|
|
/** See wxSemaphore. */
|
|
enum wxSemaError
|
|
{
|
|
wxSEMA_NO_ERROR = 0,
|
|
wxSEMA_INVALID, //!< semaphore hasn't been initialized successfully
|
|
wxSEMA_BUSY, //!< returned by TryWait() if Wait() would block
|
|
wxSEMA_TIMEOUT, //!< returned by WaitTimeout()
|
|
wxSEMA_OVERFLOW, //!< Post() would increase counter past the max
|
|
wxSEMA_MISC_ERROR
|
|
};
|
|
|
|
/**
|
|
@class wxSemaphore
|
|
|
|
wxSemaphore is a counter limiting the number of threads concurrently accessing
|
|
a shared resource. This counter is always between 0 and the maximum value
|
|
specified during the semaphore creation. When the counter is strictly greater
|
|
than 0, a call to wxSemaphore::Wait() returns immediately and decrements the
|
|
counter. As soon as it reaches 0, any subsequent calls to wxSemaphore::Wait
|
|
block and only return when the semaphore counter becomes strictly positive
|
|
again as the result of calling wxSemaphore::Post which increments the counter.
|
|
|
|
In general, semaphores are useful to restrict access to a shared resource
|
|
which can only be accessed by some fixed number of clients at the same time.
|
|
For example, when modeling a hotel reservation system a semaphore with the counter
|
|
equal to the total number of available rooms could be created. Each time a room
|
|
is reserved, the semaphore should be acquired by calling wxSemaphore::Wait
|
|
and each time a room is freed it should be released by calling wxSemaphore::Post.
|
|
|
|
@library{wxbase}
|
|
@category{threading}
|
|
*/
|
|
class wxSemaphore
|
|
{
|
|
public:
|
|
/**
|
|
Specifying a @a maxcount of 0 actually makes wxSemaphore behave as if
|
|
there is no upper limit. If @a maxcount is 1, the semaphore behaves almost as a
|
|
mutex (but unlike a mutex it can be released by a thread different from the one
|
|
which acquired it).
|
|
|
|
@a initialcount is the initial value of the semaphore which must be between
|
|
0 and @a maxcount (if it is not set to 0).
|
|
*/
|
|
wxSemaphore(int initialcount = 0, int maxcount = 0);
|
|
|
|
/**
|
|
Destructor is not virtual, don't use this class polymorphically.
|
|
*/
|
|
~wxSemaphore();
|
|
|
|
/**
|
|
Increments the semaphore count and signals one of the waiting
|
|
threads in an atomic way. Returns @e wxSEMA_OVERFLOW if the count
|
|
would increase the counter past the maximum.
|
|
|
|
@return One of:
|
|
- wxSEMA_NO_ERROR: There was no error.
|
|
- wxSEMA_INVALID : Semaphore hasn't been initialized successfully.
|
|
- wxSEMA_OVERFLOW: Post() would increase counter past the max.
|
|
- wxSEMA_MISC_ERROR: Miscellaneous error.
|
|
*/
|
|
wxSemaError Post();
|
|
|
|
/**
|
|
Same as Wait(), but returns immediately.
|
|
|
|
@return One of:
|
|
- wxSEMA_NO_ERROR: There was no error.
|
|
- wxSEMA_INVALID: Semaphore hasn't been initialized successfully.
|
|
- wxSEMA_BUSY: Returned by TryWait() if Wait() would block, i.e. the count is zero.
|
|
- wxSEMA_MISC_ERROR: Miscellaneous error.
|
|
*/
|
|
wxSemaError TryWait();
|
|
|
|
/**
|
|
Wait indefinitely until the semaphore count becomes strictly positive
|
|
and then decrement it and return.
|
|
|
|
@return One of:
|
|
- wxSEMA_NO_ERROR: There was no error.
|
|
- wxSEMA_INVALID: Semaphore hasn't been initialized successfully.
|
|
- wxSEMA_MISC_ERROR: Miscellaneous error.
|
|
*/
|
|
wxSemaError Wait();
|
|
|
|
/**
|
|
Same as Wait(), but with a timeout limit.
|
|
|
|
@return One of:
|
|
- wxSEMA_NO_ERROR: There was no error.
|
|
- wxSEMA_INVALID: Semaphore hasn't been initialized successfully.
|
|
- wxSEMA_TIMEOUT: Timeout occurred without receiving semaphore.
|
|
- wxSEMA_MISC_ERROR: Miscellaneous error.
|
|
*/
|
|
wxSemaError WaitTimeout(unsigned long timeout_millis);
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
@class wxMutexLocker
|
|
|
|
This is a small helper class to be used with wxMutex objects.
|
|
|
|
A wxMutexLocker acquires a mutex lock in the constructor and releases
|
|
(or unlocks) the mutex in the destructor making it much more difficult to
|
|
forget to release a mutex (which, in general, will promptly lead to serious
|
|
problems). See wxMutex for an example of wxMutexLocker usage.
|
|
|
|
@library{wxbase}
|
|
@category{threading}
|
|
|
|
@see wxMutex, wxCriticalSectionLocker
|
|
*/
|
|
class wxMutexLocker
|
|
{
|
|
public:
|
|
/**
|
|
Constructs a wxMutexLocker object associated with mutex and locks it.
|
|
Call IsOk() to check if the mutex was successfully locked.
|
|
*/
|
|
wxMutexLocker(wxMutex& mutex);
|
|
|
|
/**
|
|
Destructor releases the mutex if it was successfully acquired in the ctor.
|
|
*/
|
|
~wxMutexLocker();
|
|
|
|
/**
|
|
Returns @true if mutex was acquired in the constructor, @false otherwise.
|
|
*/
|
|
bool IsOk() const;
|
|
};
|
|
|
|
|
|
/**
|
|
The possible wxMutex kinds.
|
|
*/
|
|
enum wxMutexType
|
|
{
|
|
/** Normal non-recursive mutex: try to always use this one. */
|
|
wxMUTEX_DEFAULT,
|
|
|
|
/** Recursive mutex: don't use these ones with wxCondition. */
|
|
wxMUTEX_RECURSIVE
|
|
};
|
|
|
|
|
|
/**
|
|
The possible wxMutex errors.
|
|
*/
|
|
enum wxMutexError
|
|
{
|
|
/** The operation completed successfully. */
|
|
wxMUTEX_NO_ERROR = 0,
|
|
|
|
/** The mutex hasn't been initialized. */
|
|
wxMUTEX_INVALID,
|
|
|
|
/** The mutex is already locked by the calling thread. */
|
|
wxMUTEX_DEAD_LOCK,
|
|
|
|
/** The mutex is already locked by another thread. */
|
|
wxMUTEX_BUSY,
|
|
|
|
/** An attempt to unlock a mutex which is not locked. */
|
|
wxMUTEX_UNLOCKED,
|
|
|
|
/** wxMutex::LockTimeout() has timed out. */
|
|
wxMUTEX_TIMEOUT,
|
|
|
|
/** Any other error */
|
|
wxMUTEX_MISC_ERROR
|
|
};
|
|
|
|
|
|
/**
|
|
@class wxMutex
|
|
|
|
A mutex object is a synchronization object whose state is set to signaled when
|
|
it is not owned by any thread, and nonsignaled when it is owned. Its name comes
|
|
from its usefulness in coordinating mutually-exclusive access to a shared
|
|
resource as only one thread at a time can own a mutex object.
|
|
|
|
Mutexes may be recursive in the sense that a thread can lock a mutex which it
|
|
had already locked before (instead of dead locking the entire process in this
|
|
situation by starting to wait on a mutex which will never be released while the
|
|
thread is waiting) but using them is not recommended under Unix and they are
|
|
@b not recursive by default. The reason for this is that recursive
|
|
mutexes are not supported by all Unix flavours and, worse, they cannot be used
|
|
with wxCondition.
|
|
|
|
For example, when several threads use the data stored in the linked list,
|
|
modifications to the list should only be allowed to one thread at a time
|
|
because during a new node addition the list integrity is temporarily broken
|
|
(this is also called @e program @e invariant).
|
|
|
|
@code
|
|
// this variable has an "s_" prefix because it is static: seeing an "s_" in
|
|
// a multithreaded program is in general a good sign that you should use a
|
|
// mutex (or a critical section)
|
|
static wxMutex *s_mutexProtectingTheGlobalData;
|
|
|
|
// we store some numbers in this global array which is presumably used by
|
|
// several threads simultaneously
|
|
wxArrayInt s_data;
|
|
|
|
void MyThread::AddNewNode(int num)
|
|
{
|
|
// ensure that no other thread accesses the list
|
|
s_mutexProtectingTheGlobalList->Lock();
|
|
|
|
s_data.Add(num);
|
|
|
|
s_mutexProtectingTheGlobalList->Unlock();
|
|
}
|
|
|
|
// return true if the given number is greater than all array elements
|
|
bool MyThread::IsGreater(int num)
|
|
{
|
|
// before using the list we must acquire the mutex
|
|
wxMutexLocker lock(s_mutexProtectingTheGlobalData);
|
|
|
|
size_t count = s_data.Count();
|
|
for ( size_t n = 0; n < count; n++ )
|
|
{
|
|
if ( s_data[n] > num )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
@endcode
|
|
|
|
Notice how wxMutexLocker was used in the second function to ensure that the
|
|
mutex is unlocked in any case: whether the function returns true or false
|
|
(because the destructor of the local object @e lock is always called).
|
|
Using this class instead of directly using wxMutex is, in general, safer
|
|
and is even more so if your program uses C++ exceptions.
|
|
|
|
@library{wxbase}
|
|
@category{threading}
|
|
|
|
@see wxThread, wxCondition, wxMutexLocker, wxCriticalSection
|
|
*/
|
|
class wxMutex
|
|
{
|
|
public:
|
|
/**
|
|
Default constructor.
|
|
*/
|
|
wxMutex(wxMutexType type = wxMUTEX_DEFAULT);
|
|
|
|
/**
|
|
Destroys the wxMutex object.
|
|
*/
|
|
~wxMutex();
|
|
|
|
/**
|
|
Locks the mutex object.
|
|
This is equivalent to LockTimeout() with infinite timeout.
|
|
|
|
Note that if this mutex is already locked by the caller thread,
|
|
this function doesn't block but rather immediately returns.
|
|
|
|
@return One of: @c wxMUTEX_NO_ERROR, @c wxMUTEX_DEAD_LOCK.
|
|
*/
|
|
wxMutexError Lock();
|
|
|
|
/**
|
|
Try to lock the mutex object during the specified time interval.
|
|
|
|
@return One of: @c wxMUTEX_NO_ERROR, @c wxMUTEX_DEAD_LOCK, @c wxMUTEX_TIMEOUT.
|
|
*/
|
|
wxMutexError LockTimeout(unsigned long msec);
|
|
|
|
/**
|
|
Tries to lock the mutex object. If it can't, returns immediately with an error.
|
|
|
|
@return One of: @c wxMUTEX_NO_ERROR, @c wxMUTEX_BUSY.
|
|
*/
|
|
wxMutexError TryLock();
|
|
|
|
/**
|
|
Unlocks the mutex object.
|
|
|
|
@return One of: @c wxMUTEX_NO_ERROR, @c wxMUTEX_UNLOCKED.
|
|
*/
|
|
wxMutexError Unlock();
|
|
};
|
|
|
|
|
|
|
|
// ============================================================================
|
|
// Global functions/macros
|
|
// ============================================================================
|
|
|
|
/** @addtogroup group_funcmacro_thread */
|
|
//@{
|
|
|
|
/**
|
|
This macro declares a (static) critical section object named @a cs if
|
|
@c wxUSE_THREADS is 1 and does nothing if it is 0.
|
|
|
|
@header{wx/thread.h}
|
|
*/
|
|
#define wxCRIT_SECT_DECLARE(cs)
|
|
|
|
/**
|
|
This macro declares a critical section object named @a cs if
|
|
@c wxUSE_THREADS is 1 and does nothing if it is 0. As it doesn't include
|
|
the @c static keyword (unlike wxCRIT_SECT_DECLARE()), it can be used to
|
|
declare a class or struct member which explains its name.
|
|
|
|
@header{wx/thread.h}
|
|
*/
|
|
#define wxCRIT_SECT_DECLARE_MEMBER(cs)
|
|
|
|
/**
|
|
This macro creates a wxCriticalSectionLocker named @a name and associated
|
|
with the critical section @a cs if @c wxUSE_THREADS is 1 and does nothing
|
|
if it is 0.
|
|
|
|
@header{wx/thread.h}
|
|
*/
|
|
#define wxCRIT_SECT_LOCKER(name, cs)
|
|
|
|
/**
|
|
This macro combines wxCRIT_SECT_DECLARE() and wxCRIT_SECT_LOCKER(): it
|
|
creates a static critical section object and also the lock object
|
|
associated with it. Because of this, it can be only used inside a function,
|
|
not at global scope. For example:
|
|
|
|
@code
|
|
int IncCount()
|
|
{
|
|
static int s_counter = 0;
|
|
|
|
wxCRITICAL_SECTION(counter);
|
|
|
|
return ++s_counter;
|
|
}
|
|
@endcode
|
|
|
|
Note that this example assumes that the function is called the first time
|
|
from the main thread so that the critical section object is initialized
|
|
correctly by the time other threads start calling it, if this is not the
|
|
case this approach can @b not be used and the critical section must be made
|
|
a global instead.
|
|
|
|
@header{wx/thread.h}
|
|
*/
|
|
#define wxCRITICAL_SECTION(name)
|
|
|
|
/**
|
|
This macro is equivalent to
|
|
@ref wxCriticalSection::Leave "critical_section.Leave()" if
|
|
@c wxUSE_THREADS is 1 and does nothing if it is 0.
|
|
|
|
@header{wx/thread.h}
|
|
*/
|
|
#define wxLEAVE_CRIT_SECT(critical_section)
|
|
|
|
/**
|
|
This macro is equivalent to
|
|
@ref wxCriticalSection::Enter "critical_section.Enter()" if
|
|
@c wxUSE_THREADS is 1 and does nothing if it is 0.
|
|
|
|
@header{wx/thread.h}
|
|
*/
|
|
#define wxENTER_CRIT_SECT(critical_section)
|
|
|
|
/**
|
|
Returns @true if this thread is the main one. Always returns @true if
|
|
@c wxUSE_THREADS is 0.
|
|
|
|
@header{wx/thread.h}
|
|
*/
|
|
bool wxIsMainThread();
|
|
|
|
|
|
|
|
/**
|
|
This function must be called when any thread other than the main GUI thread
|
|
wants to get access to the GUI library. This function will block the
|
|
execution of the calling thread until the main thread (or any other thread
|
|
holding the main GUI lock) leaves the GUI library and no other thread will
|
|
enter the GUI library until the calling thread calls wxMutexGuiLeave().
|
|
|
|
Typically, these functions are used like this:
|
|
|
|
@code
|
|
void MyThread::Foo(void)
|
|
{
|
|
// before doing any GUI calls we must ensure that
|
|
// this thread is the only one doing it!
|
|
|
|
wxMutexGuiEnter();
|
|
|
|
// Call GUI here:
|
|
my_window->DrawSomething();
|
|
|
|
wxMutexGuiLeave();
|
|
}
|
|
@endcode
|
|
|
|
This function is only defined on platforms which support preemptive
|
|
threads and only works under some ports (wxMSW currently).
|
|
|
|
@note Under GTK, no creation of top-level windows is allowed in any thread
|
|
but the main one.
|
|
|
|
@header{wx/thread.h}
|
|
*/
|
|
void wxMutexGuiEnter();
|
|
|
|
/**
|
|
This function is only defined on platforms which support preemptive
|
|
threads.
|
|
|
|
@see wxMutexGuiEnter()
|
|
|
|
@header{wx/thread.h}
|
|
*/
|
|
void wxMutexGuiLeave();
|
|
|
|
//@}
|
|
|