atomic.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name: tests/thread/atomic.cpp
  3. // Purpose: wxAtomic??? unit test
  4. // Author: Armel Asselin
  5. // Created: 2006-12-14
  6. // Copyright: (c) 2006 Armel Asselin
  7. ///////////////////////////////////////////////////////////////////////////////
  8. // ----------------------------------------------------------------------------
  9. // headers
  10. // ----------------------------------------------------------------------------
  11. #include "testprec.h"
  12. #ifdef __BORLANDC__
  13. #pragma hdrstop
  14. #endif
  15. #ifndef WX_PRECOMP
  16. #endif // WX_PRECOMP
  17. #include "wx/atomic.h"
  18. #include "wx/thread.h"
  19. #include "wx/dynarray.h"
  20. #include "wx/log.h"
  21. WX_DEFINE_ARRAY_PTR(wxThread *, wxArrayThread);
  22. // ----------------------------------------------------------------------------
  23. // constants
  24. // ----------------------------------------------------------------------------
  25. // number of times to run the loops: the code takes too long to run if we use
  26. // the bigger value with generic atomic operations implementation
  27. #ifdef wxHAS_ATOMIC_OPS
  28. static const wxInt32 ITERATIONS_NUM = 10000000;
  29. #else
  30. static const wxInt32 ITERATIONS_NUM = 1000;
  31. #endif
  32. // ----------------------------------------------------------------------------
  33. // test class
  34. // ----------------------------------------------------------------------------
  35. class AtomicTestCase : public CppUnit::TestCase
  36. {
  37. public:
  38. AtomicTestCase() { }
  39. enum ETestType
  40. {
  41. IncAndDecMixed,
  42. IncOnly,
  43. DecOnly
  44. };
  45. private:
  46. class MyThread : public wxThread
  47. {
  48. public:
  49. MyThread(wxAtomicInt &operateOn, ETestType testType) : wxThread(wxTHREAD_JOINABLE),
  50. m_operateOn(operateOn), m_testType(testType) {}
  51. // thread execution starts here
  52. virtual void *Entry();
  53. public:
  54. wxAtomicInt &m_operateOn;
  55. ETestType m_testType;
  56. };
  57. CPPUNIT_TEST_SUITE( AtomicTestCase );
  58. CPPUNIT_TEST( TestNoThread );
  59. CPPUNIT_TEST( TestDecReturn );
  60. CPPUNIT_TEST( TestTwoThreadsMix );
  61. CPPUNIT_TEST( TestTenThreadsMix );
  62. CPPUNIT_TEST( TestTwoThreadsSeparate );
  63. CPPUNIT_TEST( TestTenThreadsSeparate );
  64. CPPUNIT_TEST_SUITE_END();
  65. void TestNoThread();
  66. void TestDecReturn();
  67. void TestTenThreadsMix() { TestWithThreads(10, IncAndDecMixed); }
  68. void TestTwoThreadsMix() { TestWithThreads(2, IncAndDecMixed); }
  69. void TestTenThreadsSeparate() { TestWithThreads(10, IncOnly); }
  70. void TestTwoThreadsSeparate() { TestWithThreads(2, IncOnly); }
  71. void TestWithThreads(int count, ETestType testtype);
  72. DECLARE_NO_COPY_CLASS(AtomicTestCase)
  73. };
  74. // register in the unnamed registry so that these tests are run by default
  75. CPPUNIT_TEST_SUITE_REGISTRATION( AtomicTestCase );
  76. // also include in its own registry so that these tests can be run alone
  77. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( AtomicTestCase, "AtomicTestCase" );
  78. void AtomicTestCase::TestNoThread()
  79. {
  80. wxAtomicInt int1 = 0,
  81. int2 = 0;
  82. for ( wxInt32 i = 0; i < ITERATIONS_NUM; ++i )
  83. {
  84. wxAtomicInc(int1);
  85. wxAtomicDec(int2);
  86. }
  87. CPPUNIT_ASSERT( int1 == ITERATIONS_NUM );
  88. CPPUNIT_ASSERT( int2 == -ITERATIONS_NUM );
  89. }
  90. void AtomicTestCase::TestDecReturn()
  91. {
  92. wxAtomicInt i(0);
  93. wxAtomicInc(i);
  94. wxAtomicInc(i);
  95. CPPUNIT_ASSERT( i == 2 );
  96. CPPUNIT_ASSERT( wxAtomicDec(i) > 0 );
  97. CPPUNIT_ASSERT( wxAtomicDec(i) == 0 );
  98. }
  99. void AtomicTestCase::TestWithThreads(int count, ETestType testType)
  100. {
  101. wxAtomicInt int1=0;
  102. wxArrayThread threads;
  103. int i;
  104. for ( i = 0; i < count; ++i )
  105. {
  106. ETestType actualThreadType;
  107. switch(testType)
  108. {
  109. default:
  110. actualThreadType = testType;
  111. break;
  112. case IncOnly:
  113. actualThreadType = (i&1)==0 ? IncOnly : DecOnly;
  114. break;
  115. }
  116. MyThread *thread = new MyThread(int1, actualThreadType);
  117. if ( thread->Create() != wxTHREAD_NO_ERROR )
  118. {
  119. wxLogError(wxT("Can't create thread!"));
  120. }
  121. else
  122. threads.Add(thread);
  123. }
  124. for ( i = 0; i < count; ++i )
  125. {
  126. threads[i]->Run();
  127. }
  128. for ( i = 0; i < count; ++i )
  129. {
  130. // each thread should return 0, else it detected some problem
  131. CPPUNIT_ASSERT (threads[i]->Wait() == (wxThread::ExitCode)0);
  132. }
  133. CPPUNIT_ASSERT( int1 == 0 );
  134. }
  135. // ----------------------------------------------------------------------------
  136. void *AtomicTestCase::MyThread::Entry()
  137. {
  138. wxInt32 negativeValuesSeen = 0;
  139. for ( wxInt32 i = 0; i < ITERATIONS_NUM; ++i )
  140. {
  141. switch ( m_testType )
  142. {
  143. case AtomicTestCase::IncAndDecMixed:
  144. wxAtomicInc(m_operateOn);
  145. wxAtomicDec(m_operateOn);
  146. if (m_operateOn < 0)
  147. ++negativeValuesSeen;
  148. break;
  149. case AtomicTestCase::IncOnly:
  150. wxAtomicInc(m_operateOn);
  151. break;
  152. case AtomicTestCase::DecOnly:
  153. wxAtomicDec(m_operateOn);
  154. break;
  155. }
  156. }
  157. return wxUIntToPtr(negativeValuesSeen);
  158. }