3535
3636namespace boost { namespace interprocess { namespace test {
3737
38+ // Once the lock is owned, announce it so that the launcher does not need to
39+ // guess it with a sleep, and either keep it until the test releases it
40+ // (m_block) or for the requested amount of time
41+ template <typename SM >
42+ void hold_lock (data<SM > *pdata, unsigned msecs)
43+ {
44+ pdata->m_acquired .signal ();
45+ if (pdata->m_block ){
46+ BOOST_INTERPROCESS_CHECK (pdata->m_release .wait ());
47+ }
48+ else if (msecs){
49+ boost::interprocess::ipcdetail::thread_sleep_ms (msecs);
50+ }
51+ }
52+
3853template <typename SM >
3954void plain_exclusive (void *arg, SM &sm)
4055{
4156 data<SM > *pdata = static_cast <data<SM >*>(arg);
4257 boost::interprocess::scoped_lock<SM > l (sm);
43- boost::interprocess::ipcdetail::thread_sleep_ms ( unsigned (3 *BaseMs));
58+ hold_lock (pdata, unsigned (3 *BaseMs));
4459 shared_val += 10 ;
4560 pdata->m_value = shared_val;
4661}
@@ -50,9 +65,7 @@ void plain_shared(void *arg, SM &sm)
5065{
5166 data<SM > *pdata = static_cast <data<SM >*>(arg);
5267 boost::interprocess::sharable_lock<SM > l (sm);
53- if (pdata->m_msecs ){
54- boost::interprocess::ipcdetail::thread_sleep_ms (unsigned (pdata->m_msecs ));
55- }
68+ hold_lock (pdata, unsigned (pdata->m_msecs ));
5669 pdata->m_value = shared_val;
5770}
5871
@@ -62,7 +75,7 @@ void try_exclusive(void *arg, SM &sm)
6275 data<SM > *pdata = static_cast <data<SM >*>(arg);
6376 boost::interprocess::scoped_lock<SM > l (sm, boost::interprocess::defer_lock);
6477 if (l.try_lock ()){
65- boost::interprocess::ipcdetail::thread_sleep_ms ( unsigned (3 *BaseMs));
78+ hold_lock (pdata, unsigned (3 *BaseMs));
6679 shared_val += 10 ;
6780 pdata->m_value = shared_val;
6881 }
@@ -74,9 +87,7 @@ void try_shared(void *arg, SM &sm)
7487 data<SM > *pdata = static_cast <data<SM >*>(arg);
7588 boost::interprocess::sharable_lock<SM > l (sm, boost::interprocess::defer_lock);
7689 if (l.try_lock ()){
77- if (pdata->m_msecs ){
78- boost::interprocess::ipcdetail::thread_sleep_ms (unsigned (pdata->m_msecs ));
79- }
90+ hold_lock (pdata, unsigned (pdata->m_msecs ));
8091 pdata->m_value = shared_val;
8192 }
8293}
@@ -96,8 +107,9 @@ void test_plain_sharable_mutex()
96107 boost::interprocess::ipcdetail::OS_thread_t tw1;
97108 boost::interprocess::ipcdetail::thread_launch (tw1, thread_adapter<SM >(plain_exclusive, &e1 , mtx));
98109
99- // Give time to e1 to grab the mutex
100- boost::interprocess::ipcdetail::thread_sleep_ms (unsigned (1 *BaseMs));
110+ // Wait until e1 really owns the mutex, so that it is guaranteed to be
111+ // the first writer no matter how loaded the machine is
112+ BOOST_INTERPROCESS_CHECK (e1 .m_acquired .wait ());
101113
102114 // Writer two launches, tries to grab the lock, "clearly"
103115 // after Writer one will already be holding it.
@@ -139,8 +151,10 @@ void test_plain_sharable_mutex()
139151 boost::interprocess::ipcdetail::OS_thread_t thr2;
140152 boost::interprocess::ipcdetail::thread_launch (thr2, thread_adapter<SM >(plain_shared,&s2, mtx));
141153
142- // Make sure they try to hold the sharable lock
143- boost::interprocess::ipcdetail::thread_sleep_ms (unsigned (1 *BaseMs));
154+ // Wait until both readers really own the sharable lock, so that they are
155+ // guaranteed to read the value before any writer changes it
156+ BOOST_INTERPROCESS_CHECK (s1.m_acquired .wait ());
157+ BOOST_INTERPROCESS_CHECK (s2.m_acquired .wait ());
144158
145159 // We launch two writers, that should block until the readers end
146160 boost::interprocess::ipcdetail::OS_thread_t tw1;
@@ -168,19 +182,22 @@ void test_try_sharable_mutex()
168182 SM mtx;
169183
170184 data<SM > s1 (1 );
171- data<SM > e1 (2 );
185+ // e1 keeps the lock until the others are done, so that they provably try to
186+ // lock an owned mutex instead of relying on e1 still sleeping by then
187+ data<SM > e1 (2 , 0 , 0 , true );
172188 data<SM > e2 (3 );
173189
174190 // We start with some specialized tests for "try" behavior
175191 shared_val = 0 ;
176192
177- // Writer one launches, holds the lock for 3*BaseMs seconds .
193+ // Writer one launches, holds the lock until released .
178194 boost::interprocess::ipcdetail::OS_thread_t tw1;
179195 boost::interprocess::ipcdetail::thread_launch (tw1, thread_adapter<SM >(try_exclusive,&e1 ,mtx));
180196
181- boost::interprocess::ipcdetail::thread_sleep_ms (unsigned (1 *BaseMs));
197+ // Wait until e1 really owns the mutex
198+ BOOST_INTERPROCESS_CHECK (e1 .m_acquired .wait ());
182199
183- // Reader one launches, "clearly" after writer #1 holds the lock
200+ // Reader one launches, after writer #1 holds the lock
184201 // and before it releases the lock.
185202 boost::interprocess::ipcdetail::OS_thread_t thr1;
186203 boost::interprocess::ipcdetail::thread_launch (thr1, thread_adapter<SM >(try_shared,&s1,mtx));
@@ -189,8 +206,10 @@ void test_try_sharable_mutex()
189206 boost::interprocess::ipcdetail::OS_thread_t tw2;
190207 boost::interprocess::ipcdetail::thread_launch (tw2, thread_adapter<SM >(try_exclusive,&e2 ,mtx));
191208
209+ // Only once both are done the lock can be released
192210 boost::interprocess::ipcdetail::thread_join (tw2);
193211 boost::interprocess::ipcdetail::thread_join (thr1);
212+ e1 .m_release .signal ();
194213 boost::interprocess::ipcdetail::thread_join (tw1);
195214
196215 BOOST_INTERPROCESS_CHECK (e1 .m_value == 10 );
@@ -217,7 +236,7 @@ void timed_exclusive(void *arg, SM &sm)
217236 }
218237
219238 if (r){
220- boost::interprocess::ipcdetail::thread_sleep_ms ( unsigned (3 *BaseMs));
239+ hold_lock (pdata, unsigned (3 *BaseMs));
221240 shared_val += 10 ;
222241 pdata->m_value = shared_val;
223242 }
@@ -242,7 +261,7 @@ void timed_shared(void *arg, SM &sm)
242261 }
243262
244263 if (r){
245- boost::interprocess::ipcdetail::thread_sleep_ms ( unsigned (3 *BaseMs));
264+ hold_lock (pdata, unsigned (3 *BaseMs));
246265 pdata->m_value = shared_val;
247266 }
248267}
@@ -253,40 +272,50 @@ void test_timed_sharable_mutex()
253272 for (int flag = 0 ; flag != (int )ETimedLockFlagsMax; ++flag)
254273 {
255274 SM mtx;
256- data<SM > e1 (3 , 3 *BaseMs, flag);
275+ // e1 keeps the lock until the lockers that must fail are done. Holding it
276+ // for a fixed time instead is not enough: under heavy CPU load a thread
277+ // can take longer to start than the hold time, find the mutex already
278+ // free and succeed, which would defeat the purpose of the test
279+ data<SM > e1 (3 , 3 *BaseMs, flag, true );
257280 data<SM > e2 (4 , 1 *BaseMs, flag);
258281 data<SM > s1 (1 , 1 *BaseMs, flag);
259- data<SM > s2 (2 , 3 *BaseMs, flag);
282+ // s2 is the only one that must succeed. It is launched just before
283+ // releasing e1, so its timeout only has to cover that short window
284+ data<SM > s2 (2 , 9 *BaseMs, flag);
260285
261286 // We begin with some specialized tests for "timed" behavior
262287
263288 shared_val = 0 ;
264289
265- // Writer one will hold the lock for 3*BaseMs seconds .
290+ // Writer one will hold the lock until released .
266291 boost::interprocess::ipcdetail::OS_thread_t tw1;
267292 boost::interprocess::ipcdetail::thread_launch (tw1, thread_adapter<SM >(timed_exclusive,&e1 ,mtx));
268293
269- boost::interprocess::ipcdetail::thread_sleep_ms (unsigned (1 *BaseMs));
270- // Writer two will "clearly" try for the lock after the readers
271- // have tried for it. Writer will wait up 1*BaseMs seconds for the lock.
272- // This write will fail.
294+ // Wait until e1 really owns the mutex, so that the others are guaranteed
295+ // to find it locked no matter how loaded the machine is
296+ BOOST_INTERPROCESS_CHECK (e1 .m_acquired .wait ());
297+
298+ // Writer two tries for the lock while writer one holds it, waiting up to
299+ // 1*BaseMs seconds. This write will fail.
273300 boost::interprocess::ipcdetail::OS_thread_t tw2;
274301 boost::interprocess::ipcdetail::thread_launch (tw2, thread_adapter<SM >(timed_exclusive,&e2 ,mtx));
275302
276- // Readers one and two will "clearly" try for the lock after writer
277- // one already holds it. 1st reader will wait 1*BaseMs seconds, and will fail
278- // to get the lock. 2nd reader will wait 3*BaseMs seconds, and will get
279- // the lock.
280-
303+ // Reader one also tries while writer one holds the lock, waiting up to
304+ // 1*BaseMs seconds, and will fail to get it.
281305 boost::interprocess::ipcdetail::OS_thread_t thr1;
282306 boost::interprocess::ipcdetail::thread_launch (thr1, thread_adapter<SM >(timed_shared,&s1,mtx));
283307
308+ // Both must have failed before the lock is released
309+ boost::interprocess::ipcdetail::thread_join (tw2);
310+ boost::interprocess::ipcdetail::thread_join (thr1);
311+
312+ // Reader two is launched and the lock released right after, so it gets
313+ // the lock and reads the value written by writer one
284314 boost::interprocess::ipcdetail::OS_thread_t thr2;
285315 boost::interprocess::ipcdetail::thread_launch (thr2, thread_adapter<SM >(timed_shared,&s2,mtx));
316+ e1 .m_release .signal ();
286317
287318 boost::interprocess::ipcdetail::thread_join (thr2);
288- boost::interprocess::ipcdetail::thread_join (thr1);
289- boost::interprocess::ipcdetail::thread_join (tw2);
290319 boost::interprocess::ipcdetail::thread_join (tw1);
291320
292321 BOOST_INTERPROCESS_CHECK (e1 .m_value == 10 );
0 commit comments