2 //=============================================================================
4 * @file Reader_Writer_Test.cpp
6 * This test program verifies the functionality of the ACE_OS
7 * implementation of readers/writer locks on Win32 and Posix
10 * @author Prashant Jain <pjain@cs.wustl.edu> and Doug C. Schmidt <d.schmidt@vanderbilt.edu>
12 //=============================================================================
14 #include "test_config.h"
15 #include "ace/Thread.h"
16 #include "ace/Thread_Manager.h"
17 #include "ace/Get_Opt.h"
18 #include "ace/Atomic_Op.h"
19 #include "ace/OS_NS_unistd.h"
20 #include "ace/Guard_T.h"
21 #include "ace/RW_Thread_Mutex.h"
22 #include "ace/Time_Value.h"
24 #if defined (ACE_HAS_THREADS)
26 // Default number of iterations.
28 // So the test doesn't run for too long . . .
29 static size_t n_iterations
= 25;
31 static size_t n_iterations
= 50;
34 // Default number of loops.
36 // thr_yield () and/or thr_equal () are expensive on VxWorks, apparently.
37 static size_t n_loops
= 10;
39 static size_t n_loops
= 100;
42 // Default number of readers.
43 static size_t n_readers
= 6;
45 // Default number of writers.
46 static size_t n_writers
= 4;
48 // Thread id of last writer.
49 static ACE_thread_t shared_data
;
51 // Lock for shared_data.
52 static ACE_RW_Thread_Mutex rw_mutex
;
54 // Count of the number of readers and writers.
55 static ACE_Atomic_Op
<ACE_Thread_Mutex
, long> current_readers
;
56 static ACE_Atomic_Op
<ACE_Thread_Mutex
, long> current_writers
;
58 // Explain usage and exit.
60 print_usage_and_die ()
63 ACE_TEXT ("usage: %n [-r n_readers] [-w n_writers] [-n iteration_count]\n")));
68 parse_args (int argc
, ACE_TCHAR
*argv
[])
70 ACE_Get_Opt
get_opt (argc
, argv
, ACE_TEXT ("r:w:n:"));
74 while ((c
= get_opt ()) != -1)
78 n_readers
= ACE_OS::atoi (get_opt
.opt_arg ());
81 n_writers
= ACE_OS::atoi (get_opt
.opt_arg ());
84 n_iterations
= ACE_OS::atoi (get_opt
.opt_arg ());
87 print_usage_and_die ();
92 // Iterate <n_iterations> each time checking that nobody modifies the data
93 // while we have a read lock.
98 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT (" (%t) reader starting\n")));
100 // We use a random pause, around 2msec with 1msec jittering.
101 int usecs
= 1000 + ACE_OS::rand() % 2000;
102 ACE_Time_Value
pause(0, usecs
);
104 for (size_t iterations
= 1; iterations
<= n_iterations
; iterations
++)
106 ACE_OS::sleep (pause
);
107 ACE_READ_GUARD_RETURN (ACE_RW_Thread_Mutex
, g
, rw_mutex
, 0);
108 // int n = ++current_readers;
109 // ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) I'm reader number %d\n"), n));
111 if (current_writers
> 0)
112 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT (" (%t) writers found!!!\n")));
114 ACE_thread_t data
= shared_data
;
116 for (size_t loop
= 1; loop
<= n_loops
; loop
++)
118 ACE_Thread::yield ();
120 if (!ACE_OS::thr_equal (shared_data
, data
))
121 ACE_DEBUG ((LM_DEBUG
,
122 ACE_TEXT (" (%t) somebody changed %d to %d\n"),
126 int result
= rw_mutex
.tryacquire_write_upgrade ();
133 ACE_DEBUG ((LM_DEBUG
,
134 ACE_TEXT ("(%t) upgraded to write lock!\n")));
136 ACE_thread_t self
= ACE_Thread::self ();
141 for (size_t loop
= 1; loop
<= n_loops
; loop
++)
143 if (ACE_OS::thr_equal (shared_data
, data
) == 0)
144 ACE_DEBUG ((LM_DEBUG
,
145 ACE_TEXT ("(%t) upgraded writer error: somebody changed %d to %d\n"),
153 else if (result
== -1 && errno
== EBUSY
)
156 // we were still a reader
158 ACE_DEBUG ((LM_DEBUG
,
159 ACE_TEXT ("(%t) could not upgrade to write lock!\n")));
163 // These #ifs should generally match the logic in OS_NS_Thread.inl.
165 # if defined (ACE_HAS_PTHREADS_UNIX98_EXT) || !defined (ACE_LACKS_RWLOCK_T)
166 // In this case we have native RW locks support, but native RW
167 // locks may not support upgrading!
168 ACE_DEBUG ((LM_DEBUG
,
169 ACE_TEXT ("(%t) %p\n"),
170 ACE_TEXT ("can't upgrade write lock"),
173 // In this case we do not have native RW locks, but therefore the
174 // emulation, which supports upgradable write locks.
175 ACE_ERROR ((LM_ERROR
,
176 ACE_TEXT ("(%t) %p\n"),
177 ACE_TEXT ("failure in upgrading to write lock"),
179 # endif /* ACE_HAS_PTHREADS_UNIX98_EXT || !ACE_LACKS_RWLOCK_T */
181 //ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) done with reading guarded data\n")));
183 ACE_DEBUG ((LM_DEBUG
,
184 ACE_TEXT ("(%t) reader finished %d iterations at %T\n"),
190 // Iterate <n_iterations> each time modifying the global data
191 // and checking that nobody steps on it while we can write it.
196 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT (" (%t) writer starting\n")));
198 // We use a random pause, around 2msec with 1msec jittering.
199 int usecs
= 1000 + ACE_OS::rand() % 2000;
200 ACE_Time_Value
pause(0, usecs
);
202 for (size_t iterations
= 1; iterations
<= n_iterations
; iterations
++)
204 ACE_OS::sleep (pause
);
206 ACE_WRITE_GUARD_RETURN (ACE_RW_Thread_Mutex
, g
, rw_mutex
, 0);
210 if (current_writers
> 1)
211 ACE_DEBUG ((LM_DEBUG
,
212 ACE_TEXT (" (%t) other writers found!!!\n")));
214 if (current_readers
> 0)
215 ACE_DEBUG ((LM_DEBUG
,
216 ACE_TEXT (" (%t) readers found!!!\n")));
218 ACE_thread_t self
= ACE_Thread::self ();
222 for (size_t loop
= 1; loop
<= n_loops
; loop
++)
224 ACE_Thread::yield ();
226 if (!ACE_OS::thr_equal (shared_data
, self
))
227 ACE_DEBUG ((LM_DEBUG
,
228 ACE_TEXT (" (%t) somebody wrote on my data %d\n"),
234 ACE_DEBUG((LM_DEBUG
, ACE_TEXT (" (%t) write %d done at %T\n"), iterations
));
239 #endif /* ACE_HAS_THREADS */
241 // Spawn off threads.
243 int run_main (int argc
, ACE_TCHAR
*argv
[])
245 ACE_START_TEST (ACE_TEXT ("Reader_Writer_Test"));
247 #if defined (ACE_HAS_THREADS)
248 parse_args (argc
, argv
);
250 current_readers
= 0; // Possibly already done
251 current_writers
= 0; // Possibly already done
253 ACE_DEBUG ((LM_DEBUG
,
254 ACE_TEXT (" (%t) main thread starting\n")));
256 if (ACE_Thread_Manager::instance ()->spawn_n (n_readers
,
257 ACE_THR_FUNC (reader
),
260 ACE_ERROR_RETURN ((LM_ERROR
,
262 ACE_TEXT ("spawn_n")), 1);
263 else if (ACE_Thread_Manager::instance ()->spawn_n (n_writers
,
264 ACE_THR_FUNC (writer
),
267 ACE_ERROR_RETURN ((LM_ERROR
,
269 ACE_TEXT ("spawn_n")), 1);
271 ACE_Thread_Manager::instance ()->wait ();
273 ACE_DEBUG ((LM_DEBUG
,
274 ACE_TEXT (" (%t) exiting main thread\n")));
276 ACE_UNUSED_ARG (argc
);
277 ACE_UNUSED_ARG (argv
);
279 ACE_TEXT ("threads not supported on this platform\n")));
280 #endif /* ACE_HAS_THREADS */