queue.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name: tests/thread/queue.cpp
  3. // Purpose: Unit test for wxMessageQueue
  4. // Author: Evgeniy Tarassov
  5. // Created: 31/10/2007
  6. // Copyright: (c) 2007 Evgeniy Tarassov
  7. // Licence: wxWindows licence
  8. ///////////////////////////////////////////////////////////////////////////////
  9. // ----------------------------------------------------------------------------
  10. // headers
  11. // ----------------------------------------------------------------------------
  12. #include "testprec.h"
  13. #ifdef __BORLANDC__
  14. #pragma hdrstop
  15. #endif
  16. #ifndef WX_PRECOMP
  17. #include "wx/dynarray.h"
  18. #include "wx/thread.h"
  19. #endif // WX_PRECOMP
  20. #include "wx/msgqueue.h"
  21. // ----------------------------------------------------------------------------
  22. // test class
  23. // ----------------------------------------------------------------------------
  24. class QueueTestCase : public CppUnit::TestCase
  25. {
  26. public:
  27. QueueTestCase() { }
  28. enum WaitTestType
  29. {
  30. WaitWithTimeout = 0,
  31. WaitInfinitlyLong
  32. };
  33. private:
  34. typedef wxMessageQueue<int> Queue;
  35. // This class represents a thread that waits (following WaitTestType type)
  36. // for exactly maxMsgCount messages from its message queue and if another
  37. // MyThread is specified, then every message received is posted
  38. // to that next thread.
  39. class MyThread : public wxThread
  40. {
  41. public:
  42. MyThread(WaitTestType type, MyThread *next, int maxMsgCount)
  43. : wxThread(wxTHREAD_JOINABLE),
  44. m_type(type), m_nextThread(next), m_maxMsgCount(maxMsgCount)
  45. {}
  46. // thread execution starts here
  47. virtual void *Entry();
  48. // Thread message queue
  49. Queue& GetQueue()
  50. {
  51. return m_queue;
  52. }
  53. private:
  54. WaitTestType m_type;
  55. MyThread* m_nextThread;
  56. int m_maxMsgCount;
  57. Queue m_queue;
  58. };
  59. WX_DEFINE_ARRAY_PTR(MyThread *, ArrayThread);
  60. CPPUNIT_TEST_SUITE( QueueTestCase );
  61. CPPUNIT_TEST( TestReceive );
  62. CPPUNIT_TEST( TestReceiveTimeout );
  63. CPPUNIT_TEST_SUITE_END();
  64. void TestReceive();
  65. void TestReceiveTimeout();
  66. DECLARE_NO_COPY_CLASS(QueueTestCase)
  67. };
  68. // register in the unnamed registry so that these tests are run by default
  69. CPPUNIT_TEST_SUITE_REGISTRATION( QueueTestCase );
  70. // also include in its own registry so that these tests can be run alone
  71. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( QueueTestCase, "QueueTestCase" );
  72. // this function creates the given number of threads and posts msgCount
  73. // messages to the last created thread which, in turn, posts all the messages
  74. // it receives to the previously created thread which does the same and so on
  75. // in cascade -- at the end, each thread will have received all msgCount
  76. // messages directly or indirectly
  77. void QueueTestCase::TestReceive()
  78. {
  79. const int msgCount = 100;
  80. const int threadCount = 10;
  81. ArrayThread threads;
  82. int i;
  83. for ( i = 0; i < threadCount; ++i )
  84. {
  85. MyThread *previousThread = i == 0 ? NULL : threads[i-1];
  86. MyThread *thread =
  87. new MyThread(WaitInfinitlyLong, previousThread, msgCount);
  88. CPPUNIT_ASSERT_EQUAL ( thread->Create(), wxTHREAD_NO_ERROR );
  89. threads.Add(thread);
  90. }
  91. for ( i = 0; i < threadCount; ++i )
  92. {
  93. threads[i]->Run();
  94. }
  95. MyThread* lastThread = threads[threadCount - 1];
  96. for ( i = 0; i < msgCount; ++i )
  97. {
  98. lastThread->GetQueue().Post(i);
  99. }
  100. for ( i = 0; i < threadCount; ++i )
  101. {
  102. // each thread should return the number of messages received.
  103. // if it returns a negative, then it detected some problem.
  104. wxThread::ExitCode code = threads[i]->Wait();
  105. CPPUNIT_ASSERT_EQUAL( code, (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR );
  106. }
  107. }
  108. // this function creates two threads, each one waiting (with a timeout) for
  109. // exactly two messages.
  110. // Exactly to messages are posted into first thread queue, but
  111. // only one message is posted to the second thread queue.
  112. // Therefore first thread should return with wxMSGQUEUE_NO_ERROR, but the second
  113. // should return wxMSGQUEUUE_TIMEOUT.
  114. void QueueTestCase::TestReceiveTimeout()
  115. {
  116. MyThread* thread1 = new MyThread(WaitWithTimeout, NULL, 2);
  117. MyThread* thread2 = new MyThread(WaitWithTimeout, NULL, 2);
  118. CPPUNIT_ASSERT_EQUAL ( thread1->Create(), wxTHREAD_NO_ERROR );
  119. CPPUNIT_ASSERT_EQUAL ( thread2->Create(), wxTHREAD_NO_ERROR );
  120. thread1->Run();
  121. thread2->Run();
  122. // Post two messages to the first thread
  123. CPPUNIT_ASSERT_EQUAL( thread1->GetQueue().Post(0), wxMSGQUEUE_NO_ERROR );
  124. CPPUNIT_ASSERT_EQUAL( thread1->GetQueue().Post(1), wxMSGQUEUE_NO_ERROR );
  125. // ...but only one message to the second
  126. CPPUNIT_ASSERT_EQUAL( thread2->GetQueue().Post(0), wxMSGQUEUE_NO_ERROR );
  127. wxThread::ExitCode code1 = thread1->Wait();
  128. wxThread::ExitCode code2 = thread2->Wait();
  129. CPPUNIT_ASSERT_EQUAL( code1, (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR );
  130. CPPUNIT_ASSERT_EQUAL( code2, (wxThread::ExitCode)wxMSGQUEUE_TIMEOUT );
  131. }
  132. // every thread tries to read exactly m_maxMsgCount messages from its queue
  133. // following the waiting strategy specified in m_type. If it succeeds then it
  134. // returns 0. Otherwise it returns the error code - one of wxMessageQueueError.
  135. void *QueueTestCase::MyThread::Entry()
  136. {
  137. int messagesReceived = 0;
  138. while ( messagesReceived < m_maxMsgCount )
  139. {
  140. wxMessageQueueError result;
  141. int msg = -1; // just to suppress "possibly uninitialized" warnings
  142. if ( m_type == WaitWithTimeout )
  143. result = m_queue.ReceiveTimeout(1000, msg);
  144. else
  145. result = m_queue.Receive(msg);
  146. if ( result == wxMSGQUEUE_MISC_ERROR )
  147. return (wxThread::ExitCode)wxMSGQUEUE_MISC_ERROR;
  148. if ( result == wxMSGQUEUE_NO_ERROR )
  149. {
  150. if ( m_nextThread != NULL )
  151. {
  152. wxMessageQueueError res = m_nextThread->GetQueue().Post(msg);
  153. if ( res == wxMSGQUEUE_MISC_ERROR )
  154. return (wxThread::ExitCode)wxMSGQUEUE_MISC_ERROR;
  155. CPPUNIT_ASSERT_EQUAL( wxMSGQUEUE_NO_ERROR, res );
  156. }
  157. ++messagesReceived;
  158. continue;
  159. }
  160. CPPUNIT_ASSERT_EQUAL ( result, wxMSGQUEUE_TIMEOUT );
  161. break;
  162. }
  163. if ( messagesReceived != m_maxMsgCount )
  164. {
  165. CPPUNIT_ASSERT_EQUAL( m_type, WaitWithTimeout );
  166. return (wxThread::ExitCode)wxMSGQUEUE_TIMEOUT;
  167. }
  168. return (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR;
  169. }