]> git.saurik.com Git - wxWidgets.git/commitdiff
Allow wxThread::Wait() and Delete() to block, even under wxMSW.
authorVadim Zeitlin <vadim@wxwidgets.org>
Mon, 14 Mar 2011 11:54:32 +0000 (11:54 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Mon, 14 Mar 2011 11:54:32 +0000 (11:54 +0000)
Add "wait mode" parameter to these methods which can be used to make them
block even under wxMSW where they currently dispatch messages when called
which can be totally unexpected.

Do keep the old behaviour for compatibility however, although it will change i
3.2.

Closes #12998.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@67185 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

12 files changed:
docs/changes.txt
include/wx/msw/apptbase.h
include/wx/msw/apptrait.h
include/wx/thread.h
interface/wx/thread.h
src/msw/app.cpp
src/msw/basemsw.cpp
src/msw/thread.cpp
src/os2/thread.cpp
src/osx/carbon/thread.cpp
src/palmos/thread.cpp
src/unix/threadpsx.cpp

index e74fcd02f157f5920df654f5985a605f0d1bee30..0a1297d4ef903b98f127ec26550f9fdc3ff5bdf5 100644 (file)
@@ -188,6 +188,13 @@ Changes in behaviour not resulting in compilation errors, please read this!
   StartDrag() virtual methods changed.  You will need to change them in your
   derived renderer class too if you override them.
 
+- wxThread::Wait() and wxThread::Delete() used to dispatch the events while
+  waiting for the thread to exit in wxMSW. They still do it in default build
+  with WXWIN_COMPATIBILITY_2_8 defined but won't dispatch any events, i.e. the
+  default wait mode will become wxTHREAD_WAIT_BLOCK in the next wxWidgets
+  release so you are strongly encouraged to upgrade your code to stop relying
+  on this behaviour.
+
 
 Changes in behaviour which may result in compilation errors
 -----------------------------------------------------------
@@ -439,6 +446,7 @@ All:
 - Added wxIMAGE_OPTION_GIF_COMMENT to read and write GIF comments (troelsk).
 - Added wxStack<> template class.
 - Added precision parameter to wxString::From[C]Double().
+- Added wxThread::Wait() and Delete() "wait mode" parameter (Catalin Raceanu).
 
 Unix:
 
index 45251e74a339b02387bcd078feb4d507feb1beb2..366741807164662a3476a8b7d7a87d49925287d4 100644 (file)
@@ -40,7 +40,7 @@ public:
 
     // wait for the handle to be signaled, return WAIT_OBJECT_0 if it is or, in
     // the GUI code, WAIT_OBJECT_0 + 1 if a Windows message arrived
-    virtual WXDWORD WaitForThread(WXHANDLE hThread) = 0;
+    virtual WXDWORD WaitForThread(WXHANDLE hThread, int flags) = 0;
 
 
 #ifndef __WXWINCE__
index 418356b169f9b83e6c5f6880b5e0f953108a7eb6..fff22eb0a284593537d7289647fcf6d7b301a1ae 100644 (file)
@@ -26,7 +26,7 @@ public:
     virtual wxTimerImpl *CreateTimerImpl(wxTimer *timer);
 #endif
     virtual bool DoMessageFromThreadWait();
-    virtual WXDWORD WaitForThread(WXHANDLE hThread);
+    virtual WXDWORD WaitForThread(WXHANDLE hThread, int flags);
 #ifndef __WXWINCE__
     virtual bool CanUseStderr() { return true; }
     virtual bool WriteToStderr(const wxString& text);
@@ -46,7 +46,7 @@ public:
 #endif
     virtual bool DoMessageFromThreadWait();
     virtual wxPortId GetToolkitVersion(int *majVer = NULL, int *minVer = NULL) const;
-    virtual WXDWORD WaitForThread(WXHANDLE hThread);
+    virtual WXDWORD WaitForThread(WXHANDLE hThread, int flags);
 
 #ifndef __WXWINCE__
     virtual bool CanUseStderr();
index fbb3cfb04207f51599b542c98e61851f09138f34..ce17e6438d93ddc5b2aa1cc9a1f9bd02b5571e66 100644 (file)
@@ -71,6 +71,21 @@ enum wxThreadKind
     wxTHREAD_JOINABLE
 };
 
+enum wxThreadWait
+{
+    wxTHREAD_WAIT_BLOCK,
+    wxTHREAD_WAIT_YIELD,       // process events while waiting; MSW only
+
+    // For compatibility reasons we use wxTHREAD_WAIT_YIELD by default as this
+    // was the default behaviour of wxMSW 2.8 but it should be avoided as it's
+    // dangerous and not portable.
+#if WXWIN_COMPATIBILITY_2_8
+    wxTHREAD_WAIT_DEFAULT = wxTHREAD_WAIT_YIELD
+#else
+    wxTHREAD_WAIT_DEFAULT = wxTHREAD_WAIT_BLOCK
+#endif
+};
+
 // defines the interval of priority
 enum
 {
@@ -516,13 +531,14 @@ public:
         // does it!
         //
         // will fill the rc pointer with the thread exit code if it's !NULL
-    wxThreadError Delete(ExitCode *rc = NULL);
+    wxThreadError Delete(ExitCode *rc = NULL,
+                         wxThreadWait waitMode = wxTHREAD_WAIT_DEFAULT);
 
         // waits for a joinable thread to finish and returns its exit code
         //
         // Returns (ExitCode)-1 on error (for example, if the thread is not
         // joinable)
-    ExitCode Wait();
+    ExitCode Wait(wxThreadWait waitMode = wxTHREAD_WAIT_DEFAULT);
 
         // kills the thread without giving it any chance to clean up - should
         // not be used under normal circumstances, use Delete() instead.
index 52b94f3128992cc7bf6cffd8408ca5a4fa3442d5..4f6962af1ec8e3c933a5013979184244edb4c61e 100644 (file)
@@ -591,6 +591,46 @@ public:
     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.
 */
@@ -1001,6 +1041,15 @@ public:
         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
@@ -1009,7 +1058,8 @@ public:
 
         See @ref thread_deletion for a broader explanation of this routine.
     */
-    wxThreadError Delete(void** rc = NULL);
+    wxThreadError Delete(ExitCode *rc = NULL,
+                         wxThreadWait waitMode = wxTHREAD_WAIT_BLOCK);
 
     /**
         Returns the number of system CPUs or -1 if the value is unknown.
@@ -1224,9 +1274,15 @@ public:
 
         This function can only be called from another thread context.
 
+        @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.
+
         See @ref thread_deletion for a broader explanation of this routine.
     */
-    ExitCode Wait();
+    ExitCode Wait(wxThreadWait flags = wxTHREAD_WAIT_BLOCK);
 
     /**
         Give the rest of the thread's time-slice to the system allowing the other
index c69c55ffa4e19c829944cb23b099fa3e3c191a34..324dd87457c9d087802a6bdb3048286777660552 100644 (file)
@@ -233,15 +233,20 @@ bool wxGUIAppTraits::DoMessageFromThreadWait()
     return evtLoop->Dispatch();
 }
 
-DWORD wxGUIAppTraits::WaitForThread(WXHANDLE hThread)
+DWORD wxGUIAppTraits::WaitForThread(WXHANDLE hThread, int flags)
 {
     // We only ever dispatch messages from the main thread and, additionally,
     // even from the main thread we shouldn't wait for the message if we don't
     // have a running event loop as we would never remove them from the message
     // queue then and so we would enter an infinite loop as
     // MsgWaitForMultipleObjects() keeps returning WAIT_OBJECT_0 + 1.
-    if ( !wxIsMainThread() || !wxEventLoop::GetActive() )
+    if ( flags == wxTHREAD_WAIT_BLOCK ||
+            !wxIsMainThread() ||
+                !wxEventLoop::GetActive() )
+    {
+        // Simple blocking wait.
         return DoSimpleWaitForThread(hThread);
+    }
 
     return ::MsgWaitForMultipleObjects
              (
index ba07b70914d1af42d6cfca1a2477d905a298c62f..df0efce82ced9eb42d9556dbd47321c721f07a45 100644 (file)
@@ -88,7 +88,7 @@ wxEventLoopBase *wxConsoleAppTraits::CreateEventLoop()
 }
 
 
-WXDWORD wxConsoleAppTraits::WaitForThread(WXHANDLE hThread)
+WXDWORD wxConsoleAppTraits::WaitForThread(WXHANDLE hThread, int WXUNUSED(flags))
 {
     return DoSimpleWaitForThread(hThread);
 }
index 30f9bca117df89ad09d8181a7268097b10177199..399a2837b500b895507e4ab5a942589c45e1a625 100644 (file)
@@ -450,6 +450,7 @@ public:
     // (politely, this is not Kill()!) to do it
     wxThreadError WaitForTerminate(wxCriticalSection& cs,
                                    wxThread::ExitCode *pRc,
+                                   wxThreadWait waitMode,
                                    wxThread *threadToDelete = NULL);
 
     // kill the thread unconditionally
@@ -703,6 +704,7 @@ wxThreadError wxThreadInternal::Kill()
 wxThreadError
 wxThreadInternal::WaitForTerminate(wxCriticalSection& cs,
                                    wxThread::ExitCode *pRc,
+                                   wxThreadWait waitMode,
                                    wxThread *threadToDelete)
 {
     // prevent the thread C++ object from disappearing as long as we are using
@@ -792,7 +794,7 @@ wxThreadInternal::WaitForTerminate(wxCriticalSection& cs,
         wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
         if ( traits )
         {
-            result = traits->WaitForThread(m_hThread);
+            result = traits->WaitForThread(m_hThread, waitMode);
         }
         else // can't wait for the thread
         {
@@ -1108,7 +1110,7 @@ wxThreadError wxThread::Resume()
 // stopping thread
 // ---------------
 
-wxThread::ExitCode wxThread::Wait()
+wxThread::ExitCode wxThread::Wait(wxThreadWait waitMode)
 {
     ExitCode rc = wxUIntToPtr(THREAD_ERROR_EXIT);
 
@@ -1117,14 +1119,14 @@ wxThread::ExitCode wxThread::Wait()
     wxCHECK_MSG( !IsDetached(), rc,
                  wxT("wxThread::Wait(): can't wait for detached thread") );
 
-    (void)m_internal->WaitForTerminate(m_critsect, &rc);
+    (void)m_internal->WaitForTerminate(m_critsect, &rc, waitMode);
 
     return rc;
 }
 
-wxThreadError wxThread::Delete(ExitCode *pRc)
+wxThreadError wxThread::Delete(ExitCode *pRc, wxThreadWait waitMode)
 {
-    return m_internal->WaitForTerminate(m_critsect, pRc, this);
+    return m_internal->WaitForTerminate(m_critsect, pRc, waitMode, this);
 }
 
 wxThreadError wxThread::Kill()
index e4d1387488163a05d1c027157835cadc9a9c0085..2dbd2268558803b37bd7f21256d0a5adf70bb554 100644 (file)
@@ -661,18 +661,18 @@ wxThreadError wxThread::Resume()
 // stopping thread
 // ---------------
 
-wxThread::ExitCode wxThread::Wait()
+wxThread::ExitCode wxThread::Wait(wxThreadWait waitMode)
 {
     // although under Windows we can wait for any thread, it's an error to
     // wait for a detached one in wxWin API
     wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
                  wxT("can't wait for detached thread") );
     ExitCode rc = (ExitCode)-1;
-    (void)Delete(&rc);
+    (void)Delete(&rc, waitMode);
     return(rc);
 }
 
-wxThreadError wxThread::Delete(ExitCode *pRc)
+wxThreadError wxThread::Delete(ExitCode *pRc, wxThreadWait WXUNUSED(waitMode))
 {
     ExitCode rc = 0;
 
index 3a55879a54ae34ce6c79db2fbfc3a5ee88d5f11f..db0a03d9b76a8b1febc8a43475bc9ec214889904 100644 (file)
@@ -940,7 +940,7 @@ wxThreadError wxThread::Resume()
 // exiting thread
 // -----------------------------------------------------------------------------
 
-wxThread::ExitCode wxThread::Wait()
+wxThread::ExitCode wxThread::Wait(wxThreadWait WXUNUSED(waitMode))
 {
     wxCHECK_MSG( This() != this, (ExitCode)-1,
                  wxT("a thread can't wait for itself") );
@@ -953,7 +953,7 @@ wxThread::ExitCode wxThread::Wait()
     return m_internal->GetExitCode();
 }
 
-wxThreadError wxThread::Delete(ExitCode *rc)
+wxThreadError wxThread::Delete(ExitCode *rc, wxThreadWait WXUNUSED(waitMode))
 {
     wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
                  wxT("a thread can't delete itself") );
index 765a778535dc5f7c9d63546bf214e7d7bf55cecf..febc8f1a676c238bb336e1ba7a4c325e8280d57e 100644 (file)
@@ -467,12 +467,12 @@ wxThreadError wxThread::Resume()
 // stopping thread
 // ---------------
 
-wxThread::ExitCode wxThread::Wait()
+wxThread::ExitCode wxThread::Wait(wxThreadWait WXUNUSED(waitMode))
 {
     return 0;
 }
 
-wxThreadError wxThread::Delete(ExitCode *pRc)
+wxThreadError wxThread::Delete(ExitCode *pRc, wxThreadWait WXUNUSED(waitMode))
 {
     return wxTHREAD_NO_ERROR;
 }
index ebb365b0d094d83b6d1df7d68fd147940f691a21..22fefee76d267440e3ab5aaa46abe801a26219f3 100644 (file)
@@ -1425,7 +1425,7 @@ wxThreadError wxThread::Resume()
 // exiting thread
 // -----------------------------------------------------------------------------
 
-wxThread::ExitCode wxThread::Wait()
+wxThread::ExitCode wxThread::Wait(wxThreadWait WXUNUSED(waitMode))
 {
     wxCHECK_MSG( This() != this, (ExitCode)-1,
                  wxT("a thread can't wait for itself") );
@@ -1438,7 +1438,7 @@ wxThread::ExitCode wxThread::Wait()
     return m_internal->GetExitCode();
 }
 
-wxThreadError wxThread::Delete(ExitCode *rc)
+wxThreadError wxThread::Delete(ExitCode *rc, wxThreadWait WXUNUSED(waitMode))
 {
     wxCHECK_MSG( This() != this, wxTHREAD_MISC_ERROR,
                  wxT("a thread can't delete itself") );