]> git.saurik.com Git - wxWidgets.git/blobdiff - include/wx/msgqueue.h
added wxMessageQueue class for inter-thread communications
[wxWidgets.git] / include / wx / msgqueue.h
diff --git a/include/wx/msgqueue.h b/include/wx/msgqueue.h
new file mode 100644 (file)
index 0000000..eda5cc9
--- /dev/null
@@ -0,0 +1,151 @@
+///////////////////////////////////////////////////////////////////////////////
+// Name:        wx/thread.h
+// Purpose:     Message queues for inter-thread communication
+// Author:      Evgeniy Tarassov
+// Created:     2007-10-31
+// RCS-ID:      $Id$
+// Copyright:   (C) 2007 TT-Solutions SARL
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_MSGQUEUE_H_
+#define _WX_MSGQUEUE_H_
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "wx/thread.h"
+
+#if wxUSE_THREADS
+
+#include "wx/beforestd.h"
+#include <queue>
+#include "wx/afterstd.h"
+
+enum wxMessageQueueError
+{
+    wxMSGQUEUE_NO_ERROR = 0, // operation completed successfully
+    wxMSGQUEUE_TIMEOUT,      // no messages received before timeout expired
+    wxMSGQUEUE_MISC_ERROR    // some unexpected (and fatal) error has occurred
+};
+
+// ---------------------------------------------------------------------------
+// Message queue allows passing message between threads.
+//
+// This class is typically used for communicating between the main and worker
+// threads. The main thread calls Post() and the worker thread calls Receive().
+//
+// For this class a message is an object of arbitrary type T. Notice that
+// typically there must be some special message indicating that the thread
+// should terminate as there is no other way to gracefully shutdown a thread
+// waiting on the message queue.
+// ---------------------------------------------------------------------------
+template <typename T>
+class wxMessageQueue
+{
+public:
+    // The type of the messages transported by this queue
+    typedef T Message;
+
+    // Default ctor creates an initially empty queue
+    wxMessageQueue()
+       : m_conditionNotEmpty(m_mutex)
+    {
+    }
+
+    // Add a message to this queue and signal the threads waiting for messages.
+    //
+    // This method is safe to call from multiple threads in parallel.
+    wxMessageQueueError Post(const Message& msg)
+    {
+        wxMutexLocker locker(m_mutex);
+
+        wxCHECK( locker.IsOk(), wxMSGQUEUE_MISC_ERROR );
+
+        m_messages.push(msg);
+
+        m_conditionNotEmpty.Signal();
+
+        return wxMSGQUEUE_NO_ERROR;
+    }
+
+    // Wait no more than timeout milliseconds until a message becomes available.
+    //
+    // Setting timeout to 0 is equivalent to an infinite timeout. See Receive().
+    wxMessageQueueError ReceiveTimeout(long timeout, T& msg)
+    {
+        wxCHECK( IsOk(), wxMSGQUEUE_MISC_ERROR );
+
+        wxMutexLocker locker(m_mutex);
+
+        wxCHECK( locker.IsOk(), wxMSGQUEUE_MISC_ERROR );
+
+        const wxMilliClock_t waitUntil = wxGetLocalTimeMillis() + timeout;
+        while ( m_messages.empty() )
+        {
+            wxCondError result = m_conditionNotEmpty.WaitTimeout(timeout);
+
+            if ( result == wxCOND_NO_ERROR )
+                continue;
+
+            wxCHECK( result == wxCOND_TIMEOUT, wxMSGQUEUE_MISC_ERROR );
+
+            const wxMilliClock_t now = wxGetLocalTimeMillis();
+
+            if ( now >= waitUntil )
+                return wxMSGQUEUE_TIMEOUT;
+
+            timeout = (waitUntil - now).ToLong();
+            wxASSERT(timeout > 0);
+        }
+
+        msg = m_messages.front();
+        m_messages.pop();
+
+        return wxMSGQUEUE_NO_ERROR;
+    }
+
+    // Same as ReceiveTimeout() but waits for as long as it takes for a message
+    // to become available (so it can't return wxMSGQUEUE_TIMEOUT)
+    wxMessageQueueError Receive(T& msg)
+    {
+        wxCHECK( IsOk(), wxMSGQUEUE_MISC_ERROR );
+
+        wxMutexLocker locker(m_mutex);
+
+        wxCHECK( locker.IsOk(), wxMSGQUEUE_MISC_ERROR );
+
+        while ( m_messages.empty() )
+        {
+            wxCondError result = m_conditionNotEmpty.Wait();
+
+            wxCHECK( result == wxCOND_NO_ERROR, wxMSGQUEUE_MISC_ERROR );
+        }
+
+        msg = m_messages.front();
+        m_messages.pop();
+
+        return wxMSGQUEUE_NO_ERROR;
+    }
+
+    // Return false only if there was a fatal error in ctor
+    bool IsOk() const
+    {
+        return m_conditionNotEmpty.IsOk();
+    }
+
+private:
+    // Disable copy ctor and assignment operator
+    wxMessageQueue(const wxMessageQueue<T>& rhs);
+    wxMessageQueue<T>& operator=(const wxMessageQueue<T>& rhs);
+
+    mutable wxMutex m_mutex;
+    wxCondition     m_conditionNotEmpty;
+
+    std::queue<T>   m_messages;
+};
+
+#endif // wxUSE_THREADS
+
+#endif // _WX_MSGQUEUE_H_