]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#1147] Converted RW lock tests to cv
authorFrancis Dupont <fdupont@isc.org>
Wed, 27 May 2020 14:08:21 +0000 (16:08 +0200)
committerFrancis Dupont <fdupont@isc.org>
Wed, 27 May 2020 14:08:21 +0000 (16:08 +0200)
src/lib/util/tests/readwrite_mutex_unittest.cc

index 4448c2b75afc5db8562a98e5762f6fef190bfb51..a379e2cde54713798e18a562fdc2d32dd4fc1b01 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <gtest/gtest.h>
 
+#include <chrono>
 #include <iostream>
 #include <thread>
 #include <unistd.h>
@@ -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<std::mutex> lock(mutex);
-                started = true;
-            }
-            // Wait to work.
-            for (;;) {
-                bool ready = false;
-                {
-                    lock_guard<std::mutex> 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<std::mutex> lock(mutex);
-                    done = true;
-                }
-                // Wait to terminate.
-                for (;;) {
-                    lock_guard<std::mutex> 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<mutex> started_lock(sync.started_mtx);
+    unique_lock<mutex> 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<mutex> work_lock(sync.work_mtx);
+        unique_lock<mutex> terminate_lock(sync.terminate_mtx);
+
+        // Signal the thread started.
+        {
+            lock_guard<mutex> 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<std::mutex> lock(mutex);
-            ready = started;
+            lock_guard<mutex> 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<std::mutex> lock(mutex);
-        work = true;
+        lock_guard<mutex> 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<std::mutex> 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<std::mutex> lock(mutex);
-        terminate = true;
+        lock_guard<mutex> 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<std::mutex> lock(mutex);
-                started = true;
-            }
-            // Wait to work.
-            for (;;) {
-                bool ready = false;
-                {
-                    lock_guard<std::mutex> 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<std::mutex> lock(mutex);
-                    done = true;
-                }
-                // Wait to terminate.
-                for (;;) {
-                    lock_guard<std::mutex> 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<mutex> started_lock(sync.started_mtx);
+    unique_lock<mutex> 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<mutex> work_lock(sync.work_mtx);
+        unique_lock<mutex> terminate_lock(sync.terminate_mtx);
+
+        // Signal the thread started.
         {
-            lock_guard<std::mutex> lock(mutex);
-            ready = started;
+            lock_guard<mutex> 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<mutex> 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<std::mutex> lock(mutex);
-        work = true;
+        lock_guard<mutex> 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<std::mutex> 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<std::mutex> lock(mutex);
-        terminate = true;
+        lock_guard<mutex> 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<std::mutex> lock(mutex);
-                started = true;
-            }
-            // Wait to work.
-            for (;;) {
-                bool ready = false;
-                {
-                    lock_guard<std::mutex> 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<std::mutex> lock(mutex);
-                    done = true;
-                }
-                // Wait to terminate.
-                for (;;) {
-                    lock_guard<std::mutex> 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<mutex> started_lock(sync.started_mtx);
+    unique_lock<mutex> 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<mutex> work_lock(sync.work_mtx);
+        unique_lock<mutex> terminate_lock(sync.terminate_mtx);
+
+        // Signal the thread started.
+        {
+            lock_guard<mutex> 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<std::mutex> lock(mutex);
-            ready = started;
+            lock_guard<mutex> 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<std::mutex> lock(mutex);
-        work = true;
+        lock_guard<mutex> 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<std::mutex> 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<std::mutex> lock(mutex);
-        terminate = true;
+        lock_guard<mutex> 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<std::mutex> lock(mutex);
-                started = true;
-            }
-            // Wait to work.
-            for (;;) {
-                bool ready = false;
-                {
-                    lock_guard<std::mutex> 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<std::mutex> lock(mutex);
-                    done = true;
-                }
-                // Wait to terminate.
-                for (;;) {
-                    lock_guard<std::mutex> 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<mutex> started_lock(sync.started_mtx);
+    unique_lock<mutex> 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<mutex> work_lock(sync.work_mtx);
+        unique_lock<mutex> terminate_lock(sync.terminate_mtx);
+
+        // Signal the thread started.
         {
-            lock_guard<std::mutex> lock(mutex);
-            ready = started;
+            lock_guard<mutex> 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<mutex> 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<std::mutex> lock(mutex);
-            work = true;
+            lock_guard<mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(mutex);
-        terminate = true;
+        lock_guard<mutex> 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<std::mutex> lock(mutex);
-                started = true;
-            }
-            // Wait to work.
-            for (;;) {
-                bool ready = false;
-                {
-                    lock_guard<std::mutex> 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<std::mutex> lock(mutex);
-                    done = true;
-                }
-                // Wait to terminate.
-                for (;;) {
-                    lock_guard<std::mutex> 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<mutex> started_lock(sync.started_mtx);
+    unique_lock<mutex> 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<mutex> work_lock(sync.work_mtx);
+        unique_lock<mutex> terminate_lock(sync.terminate_mtx);
+
+        // Signal the thread started.
+        {
+            lock_guard<mutex> 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<std::mutex> lock(mutex);
-            ready = started;
+            lock_guard<mutex> 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<std::mutex> lock(mutex);
-            work = true;
+            lock_guard<mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(mutex);
-        terminate = true;
+        lock_guard<mutex> 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<mutex> startedw_lock(syncw.started_mtx);
+    unique_lock<mutex> startedr_lock(syncr.started_mtx);
+    unique_lock<mutex> donew_lock(syncw.done_mtx);
+    unique_lock<mutex> 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<std::mutex> lock(mutex);
-                started1 = true;
-            }
-            // Wait to work.
-            for (;;) {
-                bool ready = false;
-                {
-                    lock_guard<std::mutex> 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<std::mutex> lock(mutex);
-                    done1 = true;
-                }
-                // Wait to terminate.
-                for (;;) {
-                    lock_guard<std::mutex> 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<std::mutex> lock(mutex);
-                started2 = true;
-            }
-            // Wait to work.
-            for (;;) {
-                bool ready = false;
-                {
-                    lock_guard<std::mutex> 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<std::mutex> lock(mutex);
-                    done2 = true;
-                }
-                // Wait to terminate.
-                for (;;) {
-                    lock_guard<std::mutex> lock(mutex);
-                    if (terminate2) {
-                        return;
-                    }
-                }
-            }
-        });
+    thread threadw([&rw_mutex, &syncw] () mutable -> void {
+        // Take mutexes for from main thread signals.
+        unique_lock<mutex> work_lock(syncw.work_mtx);
+        unique_lock<mutex> terminate_lock(syncw.terminate_mtx);
 
-    // Wait threads to start.
-    for (;;) {
-        bool ready = false;
+        // Signal the thread started.
         {
-            lock_guard<std::mutex> lock(mutex);
-            ready = started1 && started2;
+            lock_guard<mutex> 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<mutex> 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<mutex> work_lock(syncr.work_mtx);
+        unique_lock<mutex> terminate_lock(syncr.terminate_mtx);
+
+        // Signal the thread started.
+        {
+            lock_guard<mutex> 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<mutex> 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<std::mutex> lock(mutex);
-            work1 = true;
+            lock_guard<mutex> 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<std::mutex> 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<std::mutex> lock(mutex);
-            work2 = true;
+            lock_guard<mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(mutex);
-        terminate1 = true;
+        lock_guard<mutex> 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<std::mutex> 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<std::mutex> lock(mutex);
-        terminate2 = true;
+        lock_guard<mutex> terminate_lock(syncr.terminate_mtx);
+        syncr.terminate = true;
     }
+    syncr.terminate_cv.notify_one();
 
-    // Join the thread.
-    thread2.join();
+    // Join the writer thread.
+    threadr.join();
 }
 
 }