| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806 |
- /////////////////////////////////////////////////////////////////////////////
- // Name: thread.h
- // Purpose: interface of all thread-related wxWidgets classes
- // Author: wxWidgets team
- // Licence: wxWindows licence
- /////////////////////////////////////////////////////////////////////////////
- /** 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;
- }
- 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 and the associated condition true.
- This is a convenience overload that may be used to ignore spurious
- awakenings while waiting for a specific condition to become true.
- Equivalent to
- @code
- while ( !predicate() )
- {
- wxCondError e = Wait();
- if ( e != wxCOND_NO_ERROR )
- return e;
- }
- return wxCOND_NO_ERROR;
- @endcode
- The predicate would typically be a C++11 lambda:
- @code
- condvar.Wait([]{return value == 1;});
- @endcode
- @since 3.0
- */
- template<typename Functor>
- wxCondError Wait(const Functor& predicate);
- /**
- 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(myEVT_THREAD_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
- wxDECLARE_EVENT_TABLE();
- };
- wxDEFINE_EVENT(myEVT_THREAD_UPDATE, wxThreadEvent)
- wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
- EVT_THREAD(wxID_ANY, myEVT_THREAD_UPDATE, MyFrame::OnThreadUpdate)
- EVT_CLOSE(MyFrame::OnClose)
- wxEND_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 no one 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;
- /**
- Callback called by Delete() before actually deleting the thread.
- This function can be overridden by the derived class to perform some
- specific task when the thread is gracefully destroyed. Notice that it
- will be executed in the context of the thread that called Delete() and
- <b>not</b> in this thread's context.
- TestDestroy() will be true for the thread before OnDelete() gets
- executed.
- @since 2.9.2
- @see OnKill()
- */
- virtual void OnDelete();
- /**
- Callback called by Kill() before actually killing the thread.
- This function can be overridden by the derived class to perform some
- specific task when the thread is terminated. Notice that it will be
- executed in the context of the thread that called Kill() and <b>not</b>
- in this thread's context.
- @since 2.9.2
- @see OnDelete()
- */
- virtual void OnKill();
- /**
- @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 preferable 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();
- /**
- Try to enter the critical section (same as trying to lock a mutex).
- If it can't, immediately returns false.
- @since 2.9.3
- */
- bool TryEnter();
- /**
- 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 wait types.
- @since 2.9.2
- */
- enum wxThreadWait
- {
- /**
- No events are processed while waiting.
- This is the default under all platforms except for wxMSW.
- */
- wxTHREAD_WAIT_BLOCK,
- /**
- Yield for event dispatching while waiting.
- This flag is dangerous as it exposes the program using it to unexpected
- reentrancies in the same way as calling wxYield() function does so you
- are strongly advised to avoid its use and not wait for the thread
- termination from the main (GUI) thread at all to avoid making your
- application unresponsive.
- Also notice that this flag is not portable as it is only implemented in
- wxMSW and simply ignored under the other platforms.
- */
- wxTHREAD_WAIT_YIELD,
- /**
- Default wait mode for wxThread::Wait() and wxThread::Delete().
- For compatibility reasons, the default wait mode is currently
- wxTHREAD_WAIT_YIELD if WXWIN_COMPATIBILITY_2_8 is defined (and it is
- by default). However, as mentioned above, you're strongly encouraged to
- not use wxTHREAD_WAIT_YIELD and pass wxTHREAD_WAIT_BLOCK to wxThread
- method explicitly.
- */
- wxTHREAD_WAIT_DEFAULT = wxTHREAD_WAIT_YIELD
- };
- /**
- 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
- };
- /**
- @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 POSIX thread API. This is different from the Win32 API
- where all threads are joinable.
- By default wxThreads in wxWidgets use the @b detached behaviour.
- 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
- wxDECLARE_EVENT_TABLE();
- };
- wxBEGIN_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)
- wxEND_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->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?
- {
- wxMessageOutputDebug().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".
- 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 behaviour (i.e. it's @b detached) and
- has already deleted itself.
- Naturally, they instead attempt to use joinable threads in place of the previous
- behaviour. 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 Run() method.
- 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.
- @note
- It is not necessary to call this method since 2.9.5, Run() will create
- the thread internally. You only need to call Create() if you need to do
- something with the thread (e.g. pass its ID to an external library)
- before it starts.
- @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 address 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.
- @param rc
- The thread exit code, if rc is not NULL.
- @param waitMode
- As described in wxThreadWait documentation, wxTHREAD_WAIT_BLOCK
- should be used as the wait mode even although currently
- wxTHREAD_WAIT_YIELD is for compatibility reasons. This parameter is
- new in wxWidgets 2.9.2.
- @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(ExitCode *rc = NULL,
- wxThreadWait waitMode = wxTHREAD_WAIT_BLOCK);
- /**
- 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 0 (lowest) and 100 (highest).
- @see SetPriority()
- */
- 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.
- 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.
-
- Finally, note that once a thread has completed and its Entry() function
- returns, you cannot call Run() on it again (an assert will fail in debug
- builds or @c wxTHREAD_RUNNING will be returned in release builds).
- */
- 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 (lowest) and 100 (highest).
- The following symbolic constants can be used in addition to raw
- values in 0..100 range:
- - @c wxPRIORITY_MIN: 0
- - @c wxPRIORITY_DEFAULT: 50
- - @c wxPRIORITY_MAX: 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.
- @param flags
- As described in wxThreadWait documentation, wxTHREAD_WAIT_BLOCK
- should be used as the wait mode even although currently
- wxTHREAD_WAIT_YIELD is for compatibility reasons. This parameter is
- new in wxWidgets 2.9.2.
- See @ref thread_deletion for a broader explanation of this routine.
- */
- ExitCode Wait(wxThreadWait flags = wxTHREAD_WAIT_BLOCK);
- /**
- 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();
- //@}
|