sp_atomic_mt_test.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright (c) 2008 Peter Dimov
  2. //
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt
  6. //#define USE_MUTEX
  7. //#define USE_RWLOCK
  8. #include <boost/config.hpp>
  9. #include <boost/shared_ptr.hpp>
  10. #include <boost/bind.hpp>
  11. #if defined( USE_RWLOCK )
  12. #include <boost/thread/shared_mutex.hpp>
  13. #include <boost/thread/locks.hpp>
  14. #endif
  15. #include <boost/detail/lightweight_mutex.hpp>
  16. #include <boost/detail/lightweight_test.hpp>
  17. #include <boost/detail/lightweight_thread.hpp>
  18. #include <cstdio>
  19. #include <ctime>
  20. //
  21. int const n = 1024 * 1024;
  22. struct X
  23. {
  24. int v_; // version
  25. unsigned a_;
  26. unsigned b_;
  27. X(): v_( 0 ), a_( 1 ), b_( 1 )
  28. {
  29. }
  30. int get() const
  31. {
  32. return a_ * 7 + b_ * 11;
  33. }
  34. void set()
  35. {
  36. int tmp = get();
  37. b_ = a_;
  38. a_ = tmp;
  39. ++v_;
  40. }
  41. };
  42. static boost::shared_ptr<X> ps( new X );
  43. static boost::detail::lightweight_mutex lm;
  44. #if defined( USE_RWLOCK )
  45. static boost::shared_mutex rw;
  46. #endif
  47. static int tr = 0;
  48. void reader( int r )
  49. {
  50. int k = 0;
  51. unsigned s = 0;
  52. for( int i = 0; i < n; ++k )
  53. {
  54. #if defined( USE_MUTEX )
  55. boost::detail::lightweight_mutex::scoped_lock lock( lm );
  56. s += ps->get();
  57. BOOST_TEST( ps->v_ >= i );
  58. i = ps->v_;
  59. #elif defined( USE_RWLOCK )
  60. boost::shared_lock<boost::shared_mutex> lock( rw );
  61. s += ps->get();
  62. BOOST_TEST( ps->v_ >= i );
  63. i = ps->v_;
  64. #else
  65. boost::shared_ptr<X> p2 = boost::atomic_load( &ps );
  66. s += p2->get();
  67. BOOST_TEST( p2->v_ >= i );
  68. i = p2->v_;
  69. #endif
  70. }
  71. printf( "Reader %d: %9d iterations (%6.3fx), %u\n", r, k, (double)k / n, s );
  72. boost::detail::lightweight_mutex::scoped_lock lock( lm );
  73. tr += k;
  74. }
  75. void writer()
  76. {
  77. for( int i = 0; i < n; ++i )
  78. {
  79. #if defined( USE_MUTEX )
  80. boost::detail::lightweight_mutex::scoped_lock lock( lm );
  81. BOOST_TEST( ps->v_ == i );
  82. ps->set();
  83. #elif defined( USE_RWLOCK )
  84. boost::unique_lock<boost::shared_mutex> lock( rw );
  85. BOOST_TEST( ps->v_ == i );
  86. ps->set();
  87. #else
  88. boost::shared_ptr<X> p2( new X( *ps ) );
  89. BOOST_TEST( p2->v_ == i );
  90. p2->set();
  91. boost::atomic_store( &ps, p2 );
  92. #endif
  93. }
  94. }
  95. #if defined( BOOST_HAS_PTHREADS )
  96. char const * thmodel = "POSIX";
  97. #else
  98. char const * thmodel = "Windows";
  99. #endif
  100. int const mr = 8; // reader threads
  101. int const mw = 1; // writer thread
  102. #if defined( USE_MUTEX )
  103. char const * prim = "mutex";
  104. #elif defined( USE_RWLOCK )
  105. char const * prim = "rwlock";
  106. #else
  107. char const * prim = "atomics";
  108. #endif
  109. int main()
  110. {
  111. using namespace std; // printf, clock_t, clock
  112. printf( "Using %s threads: %dR + %dW threads, %d iterations, %s\n\n", thmodel, mr, mw, n, prim );
  113. clock_t t = clock();
  114. boost::detail::lw_thread_t a[ mr+mw ];
  115. for( int i = 0; i < mr; ++i )
  116. {
  117. boost::detail::lw_thread_create( a[ i ], boost::bind( reader, i ) );
  118. }
  119. for( int i = mr; i < mr+mw; ++i )
  120. {
  121. boost::detail::lw_thread_create( a[ i ], writer );
  122. }
  123. for( int j = 0; j < mr+mw; ++j )
  124. {
  125. boost::detail::lw_thread_join( a[ j ] );
  126. }
  127. t = clock() - t;
  128. double ts = static_cast<double>( t ) / CLOCKS_PER_SEC;
  129. printf( "%.3f seconds, %.3f reads per microsecond.\n", ts, tr / ts / 1e+6 );
  130. return boost::report_errors();
  131. }