git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@51377 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
			
				
	
	
		
			154 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| ///////////////////////////////////////////////////////////////////////////////
 | |
| // 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/stopwatch.h"
 | |
| 
 | |
| #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_
 |