1 
2 // Copyright (c) 2008 Peter Dimov
3 //
4 // Distributed under the Boost Software License, Version 1.0.
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 
8 //#define USE_MUTEX
9 //#define USE_RWLOCK
10 
11 #include <boost/config.hpp>
12 
13 #include <boost/shared_ptr.hpp>
14 #include <boost/bind.hpp>
15 
16 #if defined( USE_RWLOCK )
17 #include <boost/thread/shared_mutex.hpp>
18 #include <boost/thread/locks.hpp>
19 #endif
20 
21 #include <boost/detail/lightweight_mutex.hpp>
22 #include <boost/detail/lightweight_test.hpp>
23 #include <boost/detail/lightweight_thread.hpp>
24 
25 #include <cstdio>
26 #include <ctime>
27 
28 //
29 
30 int const n = 1024 * 1024;
31 
32 struct X
33 {
34     int v_; // version
35 
36     unsigned a_;
37     unsigned b_;
38 
XX39     X(): v_( 0 ), a_( 1 ), b_( 1 )
40     {
41     }
42 
getX43     int get() const
44     {
45         return a_ * 7 + b_ * 11;
46     }
47 
setX48     void set()
49     {
50         int tmp = get();
51 
52         b_ = a_;
53         a_ = tmp;
54 
55         ++v_;
56     }
57 };
58 
59 static boost::shared_ptr<X> ps( new X );
60 
61 static boost::detail::lightweight_mutex lm;
62 
63 #if defined( USE_RWLOCK )
64 static boost::shared_mutex rw;
65 #endif
66 
67 static int tr = 0;
68 
reader(int r)69 void reader( int r )
70 {
71     int k = 0;
72     unsigned s = 0;
73 
74     for( int i = 0; i < n; ++k )
75     {
76 #if defined( USE_MUTEX )
77 
78         boost::detail::lightweight_mutex::scoped_lock lock( lm );
79 
80         s += ps->get();
81 
82         BOOST_TEST( ps->v_ >= i );
83         i = ps->v_;
84 
85 #elif defined( USE_RWLOCK )
86 
87         boost::shared_lock<boost::shared_mutex> lock( rw );
88 
89         s += ps->get();
90 
91         BOOST_TEST( ps->v_ >= i );
92         i = ps->v_;
93 
94 #else
95 
96         boost::shared_ptr<X> p2 = boost::atomic_load( &ps );
97 
98         s += p2->get();
99 
100         BOOST_TEST( p2->v_ >= i );
101         i = p2->v_;
102 
103 #endif
104     }
105 
106     printf( "Reader %d: %9d iterations (%6.3fx), %u\n", r, k, (double)k / n, s );
107 
108     boost::detail::lightweight_mutex::scoped_lock lock( lm );
109     tr += k;
110 }
111 
writer()112 void writer()
113 {
114     for( int i = 0; i < n; ++i )
115     {
116 #if defined( USE_MUTEX )
117 
118         boost::detail::lightweight_mutex::scoped_lock lock( lm );
119 
120         BOOST_TEST( ps->v_ == i );
121         ps->set();
122 
123 #elif defined( USE_RWLOCK )
124 
125         boost::unique_lock<boost::shared_mutex> lock( rw );
126 
127         BOOST_TEST( ps->v_ == i );
128         ps->set();
129 
130 #else
131 
132         boost::shared_ptr<X> p2( new X( *ps ) );
133 
134         BOOST_TEST( p2->v_ == i );
135         p2->set();
136 
137         boost::atomic_store( &ps, p2 );
138 
139 #endif
140     }
141 }
142 
143 #if defined( BOOST_HAS_PTHREADS )
144   char const * thmodel = "POSIX";
145 #else
146   char const * thmodel = "Windows";
147 #endif
148 
149 int const mr = 8; // reader threads
150 int const mw = 1; // writer thread
151 
152 #if defined( USE_MUTEX )
153   char const * prim = "mutex";
154 #elif defined( USE_RWLOCK )
155   char const * prim = "rwlock";
156 #else
157   char const * prim = "atomics";
158 #endif
159 
main()160 int main()
161 {
162     using namespace std; // printf, clock_t, clock
163 
164     printf( "Using %s threads: %dR + %dW threads, %d iterations, %s\n\n", thmodel, mr, mw, n, prim );
165 
166     clock_t t = clock();
167 
168     pthread_t a[ mr+mw ];
169 
170     for( int i = 0; i < mr; ++i )
171     {
172         boost::detail::lw_thread_create( a[ i ], boost::bind( reader, i ) );
173     }
174 
175     for( int i = mr; i < mr+mw; ++i )
176     {
177         boost::detail::lw_thread_create( a[ i ], writer );
178     }
179 
180     for( int j = 0; j < mr+mw; ++j )
181     {
182         pthread_join( a[ j ], 0 );
183     }
184 
185     t = clock() - t;
186 
187     double ts = static_cast<double>( t ) / CLOCKS_PER_SEC;
188     printf( "%.3f seconds, %.3f reads per microsecond.\n", ts, tr / ts / 1e+6 );
189 
190     return boost::report_errors();
191 }
192