From: Francis Dupont Date: Wed, 27 May 2020 14:08:21 +0000 (+0200) Subject: [#1147] Converted RW lock tests to cv X-Git-Tag: Kea-1.7.9~115 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0b693032d44567daf8d43575516b6b96544aa4ef;p=thirdparty%2Fkea.git [#1147] Converted RW lock tests to cv --- diff --git a/src/lib/util/tests/readwrite_mutex_unittest.cc b/src/lib/util/tests/readwrite_mutex_unittest.cc index 4448c2b75a..a379e2cde5 100644 --- a/src/lib/util/tests/readwrite_mutex_unittest.cc +++ b/src/lib/util/tests/readwrite_mutex_unittest.cc @@ -10,6 +10,7 @@ #include +#include #include #include #include @@ -33,89 +34,85 @@ TEST(ReadWriteMutexTest, basicWrite) { // Verify read lock guard using a thread. TEST(ReadWriteMutexTest, read) { - mutex mutex; ReadWriteMutex rw_mutex; - bool started = false; - bool work = false; - bool done = false; - bool terminate = false; - - // Create a thread. - thread thread( - [&mutex, &rw_mutex, &started, &work, &done, &terminate] () - mutable -> void { - // Signal the thread started. - { - lock_guard lock(mutex); - started = true; - } - // Wait to work. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = work; - } - if (ready) { - break; - } - usleep(100); - } - { - // Enter a read lock guard. - ReadLockGuard rwlock(rw_mutex); - { - // Signal the thread holds the guard. - lock_guard lock(mutex); - done = true; - } - // Wait to terminate. - for (;;) { - lock_guard lock(mutex); - if (terminate) { - return; - } - } - } - }); - // Wait thread to start. - for (;;) { - bool ready = false; + // Synchronization objects for the work thread. + struct { + bool started = false; + mutex started_mtx; + condition_variable started_cv; + bool work = false; + mutex work_mtx; + condition_variable work_cv; + bool done = false; + mutex done_mtx; + condition_variable done_cv; + bool terminate = false; + mutex terminate_mtx; + condition_variable terminate_cv; + } sync; + + // Take mutexes for from work thread signals. + unique_lock started_lock(sync.started_mtx); + unique_lock done_lock(sync.done_mtx); + + // Create a work thread. + thread thread([&rw_mutex, &sync] () mutable -> void { + // Take mutexes for from main thread signals. + unique_lock work_lock(sync.work_mtx); + unique_lock terminate_lock(sync.terminate_mtx); + + // Signal the thread started. + { + lock_guard lock(sync.started_mtx); + sync.started = true; + } + sync.started_cv.notify_one(); + + // Wait for work. + while (!sync.work) { + sync.work_cv.wait(work_lock); + } + + // Enter a read lock guard. + ReadLockGuard rwlock(rw_mutex); + + // Signal the thread holds the guard. { - lock_guard lock(mutex); - ready = started; + lock_guard done_lock(sync.done_mtx); + sync.done = true; } - if (ready) { - break; + sync.done_cv.notify_one(); + + // Wait to terminate. + while (!sync.terminate) { + sync.terminate_cv.wait(terminate_lock); } - usleep(100); + }); + + // Wait work thread to start. + while (!sync.started) { + sync.started_cv.wait(started_lock); } // Signal the thread to work. { - lock_guard lock(mutex); - work = true; + lock_guard work_lock(sync.work_mtx); + sync.work = true; } + sync.work_cv.notify_one(); - // Wait thread to hold the read lock guard. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = done; - } - if (ready) { - break; - } - usleep(100); + // Wait thread to hold the read lock. + while (!sync.done) { + sync.done_cv.wait(done_lock); } // Signal the thread to terminate. { - lock_guard lock(mutex); - terminate = true; + lock_guard terminate_lock(sync.terminate_mtx); + sync.terminate = true; } + sync.terminate_cv.notify_one(); // Join the thread. thread.join(); @@ -123,89 +120,85 @@ TEST(ReadWriteMutexTest, read) { // Verify write lock guard using a thread. TEST(ReadWriteMutexTest, write) { - mutex mutex; ReadWriteMutex rw_mutex; - bool started = false; - bool work = false; - bool done = false; - bool terminate = false; - - // Create a thread. - thread thread( - [&mutex, &rw_mutex, &started, &work, &done, &terminate] () - mutable -> void { - // Signal the thread started. - { - lock_guard lock(mutex); - started = true; - } - // Wait to work. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = work; - } - if (ready) { - break; - } - usleep(100); - } - { - // Enter a write lock guard. - WriteLockGuard rwlock(rw_mutex); - { - // Signal the thread holds the guard. - lock_guard lock(mutex); - done = true; - } - // Wait to terminate. - for (;;) { - lock_guard lock(mutex); - if (terminate) { - return; - } - } - } - }); - // Wait thread to start. - for (;;) { - bool ready = false; + // Synchronization objects for the work thread. + struct { + bool started = false; + mutex started_mtx; + condition_variable started_cv; + bool work = false; + mutex work_mtx; + condition_variable work_cv; + bool done = false; + mutex done_mtx; + condition_variable done_cv; + bool terminate = false; + mutex terminate_mtx; + condition_variable terminate_cv; + } sync; + + // Take mutexes for from work thread signals. + unique_lock started_lock(sync.started_mtx); + unique_lock done_lock(sync.done_mtx); + + // Create a work thread. + thread thread([&rw_mutex, &sync] () mutable -> void { + // Take mutexes for from main thread signals. + unique_lock work_lock(sync.work_mtx); + unique_lock terminate_lock(sync.terminate_mtx); + + // Signal the thread started. { - lock_guard lock(mutex); - ready = started; + lock_guard lock(sync.started_mtx); + sync.started = true; } - if (ready) { - break; + sync.started_cv.notify_one(); + + // Wait for work. + while (!sync.work) { + sync.work_cv.wait(work_lock); + } + + // Enter a write lock guard. + WriteLockGuard rwlock(rw_mutex); + + // Signal the thread holds the guard. + { + lock_guard done_lock(sync.done_mtx); + sync.done = true; + } + sync.done_cv.notify_one(); + + // Wait to terminate. + while (!sync.terminate) { + sync.terminate_cv.wait(terminate_lock); } - usleep(100); + }); + + // Wait work thread to start. + while (!sync.started) { + sync.started_cv.wait(started_lock); } // Signal the thread to work. { - lock_guard lock(mutex); - work = true; + lock_guard work_lock(sync.work_mtx); + sync.work = true; } + sync.work_cv.notify_one(); - // Wait thread to hold the write lock guard. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = done; - } - if (ready) { - break; - } - usleep(100); + // Wait thread to hold the write lock. + while (!sync.done) { + sync.done_cv.wait(done_lock); } // Signal the thread to terminate. { - lock_guard lock(mutex); - terminate = true; + lock_guard terminate_lock(sync.terminate_mtx); + sync.terminate = true; } + sync.terminate_cv.notify_one(); // Join the thread. thread.join(); @@ -213,92 +206,88 @@ TEST(ReadWriteMutexTest, write) { // Verify read lock guard can be acquired by multiple threads. TEST(ReadWriteMutexTest, readRead) { - mutex mutex; ReadWriteMutex rw_mutex; - bool started = false; - bool work = false; - bool done = false; - bool terminate = false; - - // Create a thread. - thread thread( - [&mutex, &rw_mutex, &started, &work, &done, &terminate] () - mutable -> void { - // Signal the thread started. - { - lock_guard lock(mutex); - started = true; - } - // Wait to work. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = work; - } - if (ready) { - break; - } - usleep(100); - } - { - // Enter a read lock guard. - ReadLockGuard rwlock(rw_mutex); - { - // Signal the thread holds the guard. - lock_guard lock(mutex); - done = true; - } - // Wait to terminate. - for (;;) { - lock_guard lock(mutex); - if (terminate) { - return; - } - } - } - }); - // Enter a read load guard. - ReadLockGuard rwlock(rw_mutex); + // Synchronization objects for the work thread. + struct { + bool started = false; + mutex started_mtx; + condition_variable started_cv; + bool work = false; + mutex work_mtx; + condition_variable work_cv; + bool done = false; + mutex done_mtx; + condition_variable done_cv; + bool terminate = false; + mutex terminate_mtx; + condition_variable terminate_cv; + } sync; + + // Take mutexes for from work thread signals. + unique_lock started_lock(sync.started_mtx); + unique_lock done_lock(sync.done_mtx); + + // Create a work thread. + thread thread([&rw_mutex, &sync] () mutable -> void { + // Take mutexes for from main thread signals. + unique_lock work_lock(sync.work_mtx); + unique_lock terminate_lock(sync.terminate_mtx); + + // Signal the thread started. + { + lock_guard lock(sync.started_mtx); + sync.started = true; + } + sync.started_cv.notify_one(); + + // Wait for work. + while (!sync.work) { + sync.work_cv.wait(work_lock); + } - // Wait thread to start.. - for (;;) { - bool ready = false; + // Enter a read lock guard. + ReadLockGuard rwlock(rw_mutex); + + // Signal the thread holds the guard. { - lock_guard lock(mutex); - ready = started; + lock_guard done_lock(sync.done_mtx); + sync.done = true; } - if (ready) { - break; + sync.done_cv.notify_one(); + + // Wait to terminate. + while (!sync.terminate) { + sync.terminate_cv.wait(terminate_lock); } - usleep(100); + }); + + // Enter a read load guard. + ReadLockGuard rwlock(rw_mutex); + + // Wait work thread to start. + while (!sync.started) { + sync.started_cv.wait(started_lock); } // Signal the thread to work. { - lock_guard lock(mutex); - work = true; + lock_guard work_lock(sync.work_mtx); + sync.work = true; } + sync.work_cv.notify_one(); - // Wait thread to hold the read lock guard. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = done; - } - if (ready) { - break; - } - usleep(100); + // Wait thread to hold the read lock. + while (!sync.done) { + sync.done_cv.wait(done_lock); } // Signal the thread to terminate. { - lock_guard lock(mutex); - terminate = true; + lock_guard terminate_lock(sync.terminate_mtx); + sync.terminate = true; } + sync.terminate_cv.notify_one(); // Join the thread. thread.join(); @@ -306,63 +295,65 @@ TEST(ReadWriteMutexTest, readRead) { // Verify write lock guard is exclusive of a reader. TEST(ReadWriteMutexTest, readWrite) { - mutex mutex; ReadWriteMutex rw_mutex; - bool started = false; - bool work = false; - bool done = false; - bool terminate = false; - - // Create a thread. - thread thread( - [&mutex, &rw_mutex, &started, &work, &done, &terminate] () - mutable -> void { - // Signal the thread started. - { - lock_guard lock(mutex); - started = true; - } - // Wait to work. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = work; - } - if (ready) { - break; - } - usleep(100); - } - { - // Enter a write lock guard. - WriteLockGuard rwlock(rw_mutex); - { - // Signal the thread holds the guard. - lock_guard lock(mutex); - done = true; - } - // Wait to terminate. - for (;;) { - lock_guard lock(mutex); - if (terminate) { - return; - } - } - } - }); - // Wait thread to start. - for (;;) { - bool ready = false; + // Synchronization objects for the work thread. + struct { + bool started = false; + mutex started_mtx; + condition_variable started_cv; + bool work = false; + mutex work_mtx; + condition_variable work_cv; + bool done = false; + mutex done_mtx; + condition_variable done_cv; + bool terminate = false; + mutex terminate_mtx; + condition_variable terminate_cv; + } sync; + + // Take mutexes for from work thread signals. + unique_lock started_lock(sync.started_mtx); + unique_lock done_lock(sync.done_mtx); + + // Create a work thread. + thread thread([&rw_mutex, &sync] () mutable -> void { + // Take mutexes for from main thread signals. + unique_lock work_lock(sync.work_mtx); + unique_lock terminate_lock(sync.terminate_mtx); + + // Signal the thread started. { - lock_guard lock(mutex); - ready = started; + lock_guard lock(sync.started_mtx); + sync.started = true; } - if (ready) { - break; + sync.started_cv.notify_one(); + + // Wait for work. + while (!sync.work) { + sync.work_cv.wait(work_lock); + } + + // Enter a write lock guard. + WriteLockGuard rwlock(rw_mutex); + + // Signal the thread holds the guard. + { + lock_guard done_lock(sync.done_mtx); + sync.done = true; + } + sync.done_cv.notify_one(); + + // Wait to terminate. + while (!sync.terminate) { + sync.terminate_cv.wait(terminate_lock); } - usleep(100); + }); + + // Wait work thread to start. + while (!sync.started) { + sync.started_cv.wait(started_lock); } { @@ -371,38 +362,39 @@ TEST(ReadWriteMutexTest, readWrite) { // Signal the thread to work. { - lock_guard lock(mutex); - work = true; + lock_guard work_lock(sync.work_mtx); + sync.work = true; } + sync.work_cv.notify_one(); + // Verify the work thread is waiting for the write lock. cout << "pausing for one second\n"; - usleep(1000000); - bool ready = false; - { - lock_guard lock(mutex); - ready = done; + bool timeout = false; + while (!timeout && !sync.done) { + auto one_sec = chrono::seconds(1); + auto status = sync.done_cv.wait_for(done_lock, one_sec); + if (status == cv_status::timeout) { + timeout = true; + } } - EXPECT_FALSE(ready); + + EXPECT_FALSE(sync.done); + EXPECT_TRUE(timeout); + + // Exiting the read lock guard. } - // Wait thread to hold the write lock guard. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = done; - } - if (ready) { - break; - } - usleep(100); + // Wait thread to hold the write lock. + while (!sync.done) { + sync.done_cv.wait(done_lock); } // Signal the thread to terminate. { - lock_guard lock(mutex); - terminate = true; + lock_guard terminate_lock(sync.terminate_mtx); + sync.terminate = true; } + sync.terminate_cv.notify_one(); // Join the thread. thread.join(); @@ -410,63 +402,65 @@ TEST(ReadWriteMutexTest, readWrite) { // Verify write lock guard is exclusive of a writer. TEST(ReadWriteMutexTest, writeWrite) { - mutex mutex; ReadWriteMutex rw_mutex; - bool started = false; - bool work = false; - bool done = false; - bool terminate = false; - - // Create a thread. - thread thread( - [&mutex, &rw_mutex, &started, &work, &done, &terminate] () - mutable -> void { - // Signal the thread started. - { - lock_guard lock(mutex); - started = true; - } - // Wait to work. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = work; - } - if (ready) { - break; - } - usleep(100); - } - { - // Enter a write lock guard. - WriteLockGuard rwlock(rw_mutex); - { - // Signal the thread holds the guard. - lock_guard lock(mutex); - done = true; - } - // Wait to terminate. - for (;;) { - lock_guard lock(mutex); - if (terminate) { - return; - } - } - } - }); - // Wait thread to start. - for (;;) { - bool ready = false; + // Synchronization objects for the work thread. + struct { + bool started = false; + mutex started_mtx; + condition_variable started_cv; + bool work = false; + mutex work_mtx; + condition_variable work_cv; + bool done = false; + mutex done_mtx; + condition_variable done_cv; + bool terminate = false; + mutex terminate_mtx; + condition_variable terminate_cv; + } sync; + + // Take mutexes for from work thread signals. + unique_lock started_lock(sync.started_mtx); + unique_lock done_lock(sync.done_mtx); + + // Create a work thread. + thread thread([&rw_mutex, &sync] () mutable -> void { + // Take mutexes for from main thread signals. + unique_lock work_lock(sync.work_mtx); + unique_lock terminate_lock(sync.terminate_mtx); + + // Signal the thread started. + { + lock_guard lock(sync.started_mtx); + sync.started = true; + } + sync.started_cv.notify_one(); + + // Wait for work. + while (!sync.work) { + sync.work_cv.wait(work_lock); + } + + // Enter a write lock guard. + WriteLockGuard rwlock(rw_mutex); + + // Signal the thread holds the guard. { - lock_guard lock(mutex); - ready = started; + lock_guard done_lock(sync.done_mtx); + sync.done = true; } - if (ready) { - break; + sync.done_cv.notify_one(); + + // Wait to terminate. + while (!sync.terminate) { + sync.terminate_cv.wait(terminate_lock); } - usleep(100); + }); + + // Wait work thread to start. + while (!sync.started) { + sync.started_cv.wait(started_lock); } { @@ -475,38 +469,39 @@ TEST(ReadWriteMutexTest, writeWrite) { // Signal the thread to work. { - lock_guard lock(mutex); - work = true; + lock_guard work_lock(sync.work_mtx); + sync.work = true; } + sync.work_cv.notify_one(); + // Verify the work thread is waiting for the write lock. cout << "pausing for one second\n"; - usleep(1000000); - bool ready = false; - { - lock_guard lock(mutex); - ready = done; + bool timeout = false; + while (!timeout && !sync.done) { + auto one_sec = chrono::seconds(1); + auto status = sync.done_cv.wait_for(done_lock, one_sec); + if (status == cv_status::timeout) { + timeout = true; + } } - EXPECT_FALSE(ready); + + EXPECT_FALSE(sync.done); + EXPECT_TRUE(timeout); + + // Exiting the write lock guard. } - // Wait thread to hold the write lock guard. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = done; - } - if (ready) { - break; - } - usleep(100); + // Wait thread to hold the write lock. + while (!sync.done) { + sync.done_cv.wait(done_lock); } // Signal the thread to terminate. { - lock_guard lock(mutex); - terminate = true; + lock_guard terminate_lock(sync.terminate_mtx); + sync.terminate = true; } + sync.terminate_cv.notify_one(); // Join the thread. thread.join(); @@ -514,106 +509,104 @@ TEST(ReadWriteMutexTest, writeWrite) { // Verify that a writer has the preference. TEST(ReadWriteMutexTest, readWriteRead) { - mutex mutex; ReadWriteMutex rw_mutex; - bool started1 = false; - bool started2 = false; - bool work1 = false; - bool work2 = false; - bool done1 = false; - bool done2 = false; - bool terminate1 = false; - bool terminate2 = false; + + // Synchronization objects for the work threads. + struct { + bool started = false; + mutex started_mtx; + condition_variable started_cv; + bool work = false; + mutex work_mtx; + condition_variable work_cv; + bool done = false; + mutex done_mtx; + condition_variable done_cv; + bool terminate = false; + mutex terminate_mtx; + condition_variable terminate_cv; + } syncw, syncr; + + // Take mutexes for from work thread signals. + unique_lock startedw_lock(syncw.started_mtx); + unique_lock startedr_lock(syncr.started_mtx); + unique_lock donew_lock(syncw.done_mtx); + unique_lock doner_lock(syncr.done_mtx); // First thread is a writer. - thread thread1( - [&mutex, &rw_mutex, &started1, &work1, &done1, &terminate1] () - mutable -> void { - // Signal the thread started. - { - lock_guard lock(mutex); - started1 = true; - } - // Wait to work. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = work1; - } - if (ready) { - break; - } - usleep(100); - } - { - // Enter a write lock guard. - WriteLockGuard rwlock(rw_mutex); - { - // Signal the thread holds the guard. - lock_guard lock(mutex); - done1 = true; - } - // Wait to terminate. - for (;;) { - lock_guard lock(mutex); - if (terminate1) { - return; - } - } - } - }); - - // Second thread is a writer. - thread thread2( - [&mutex, &rw_mutex, &started2, &work2, &done2, &terminate2] () - mutable -> void { - // Signal the thread started. - { - lock_guard lock(mutex); - started2 = true; - } - // Wait to work. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = work2; - } - if (ready) { - break; - } - usleep(100); - } - { - // Enter a read lock guard. - ReadLockGuard rwlock(rw_mutex); - { - // Signal the thread holds the guard. - lock_guard lock(mutex); - done2 = true; - } - // Wait to terminate. - for (;;) { - lock_guard lock(mutex); - if (terminate2) { - return; - } - } - } - }); + thread threadw([&rw_mutex, &syncw] () mutable -> void { + // Take mutexes for from main thread signals. + unique_lock work_lock(syncw.work_mtx); + unique_lock terminate_lock(syncw.terminate_mtx); - // Wait threads to start. - for (;;) { - bool ready = false; + // Signal the thread started. { - lock_guard lock(mutex); - ready = started1 && started2; + lock_guard lock(syncw.started_mtx); + syncw.started = true; } - if (ready) { - break; + syncw.started_cv.notify_one(); + + // Wait for work. + while (!syncw.work) { + syncw.work_cv.wait(work_lock); + } + + // Enter a write lock guard. + WriteLockGuard rwlock(rw_mutex); + + // Signal the thread holds the guard. + { + lock_guard done_lock(syncw.done_mtx); + syncw.done = true; } - usleep(100); + syncw.done_cv.notify_one(); + + // Wait to terminate. + while (!syncw.terminate) { + syncw.terminate_cv.wait(terminate_lock); + } + }); + + // Second thread is a reader. + thread threadr([&rw_mutex, &syncr] () mutable -> void { + // Take mutexes for from main thread signals. + unique_lock work_lock(syncr.work_mtx); + unique_lock terminate_lock(syncr.terminate_mtx); + + // Signal the thread started. + { + lock_guard lock(syncr.started_mtx); + syncr.started = true; + } + syncr.started_cv.notify_one(); + + // Wait for work. + while (!syncr.work) { + syncr.work_cv.wait(work_lock); + } + + // Enter a read lock guard. + ReadLockGuard rwlock(rw_mutex); + + // Signal the thread holds the guard. + { + lock_guard done_lock(syncr.done_mtx); + syncr.done = true; + } + syncr.done_cv.notify_one(); + + // Wait to terminate. + while (!syncr.terminate) { + syncr.terminate_cv.wait(terminate_lock); + } + }); + + // Wait threads to started. + while (!syncw.started) { + syncw.started_cv.wait(startedw_lock); + } + while (!syncr.started) { + syncr.started_cv.wait(startedr_lock); } { @@ -622,75 +615,92 @@ TEST(ReadWriteMutexTest, readWriteRead) { // Signal the writer thread to work. { - lock_guard lock(mutex); - work1 = true; + lock_guard work_lock(syncw.work_mtx); + syncw.work = true; } + syncw.work_cv.notify_one(); + // Verify the writer thread is waiting for the write lock. cout << "pausing for one second\n"; - usleep(1000000); - bool ready = false; - { - lock_guard lock(mutex); - ready = done1; + bool timeout = false; + while (!timeout && !syncw.done) { + auto one_sec = chrono::seconds(1); + auto status = syncw.done_cv.wait_for(donew_lock, one_sec); + if (status == cv_status::timeout) { + timeout = true; + } } - EXPECT_FALSE(ready); + + EXPECT_FALSE(syncw.done); + EXPECT_TRUE(timeout); // Signal the reader thread to work. { - lock_guard lock(mutex); - work2 = true; + lock_guard work_lock(syncr.work_mtx); + syncr.work = true; } + syncr.work_cv.notify_one(); + // Verify the reader thread is waiting for the rea lock. cout << "pausing for one second\n"; - usleep(1000000); - ready = false; - { - lock_guard lock(mutex); - ready = done2; + timeout = false; + while (!timeout && !syncr.done) { + auto one_sec = chrono::seconds(1); + auto status = syncr.done_cv.wait_for(doner_lock, one_sec); + if (status == cv_status::timeout) { + timeout = true; + } } - EXPECT_FALSE(ready); + + EXPECT_FALSE(syncr.done); + EXPECT_TRUE(timeout); + + // Exiting the read lock guard. } + // Verify the reader thread is still waiting for the read lock. cout << "pausing for one second\n"; - usleep(1000000); - { - bool ready = false; - { - lock_guard lock(mutex); - ready = done2; + bool timeout = false; + while (!timeout && !syncr.done) { + auto one_sec = chrono::seconds(1); + auto status = syncr.done_cv.wait_for(doner_lock, one_sec); + if (status == cv_status::timeout) { + timeout = true; } - EXPECT_FALSE(ready); } + + EXPECT_FALSE(syncr.done); + EXPECT_TRUE(timeout); + + // Wait writer thread to hold the write lock. + while (!syncw.done) { + syncw.done_cv.wait(donew_lock); + } + // Signal the writer thread to terminate. { - lock_guard lock(mutex); - terminate1 = true; + lock_guard terminate_lock(syncw.terminate_mtx); + syncw.terminate = true; } + syncw.terminate_cv.notify_one(); // Join the writer thread. - thread1.join(); + threadw.join(); - // Wait reader thread to hold the read lock guard. - for (;;) { - bool ready = false; - { - lock_guard lock(mutex); - ready = done2; - } - if (ready) { - break; - } - usleep(100); + // Wait reader thread to hold the read lock. + while (!syncr.done) { + syncr.done_cv.wait(doner_lock); } // Signal the reader thread to terminate. { - lock_guard lock(mutex); - terminate2 = true; + lock_guard terminate_lock(syncr.terminate_mtx); + syncr.terminate = true; } + syncr.terminate_cv.notify_one(); - // Join the thread. - thread2.join(); + // Join the writer thread. + threadr.join(); } }