#include <gtest/gtest.h>
+#include <chrono>
#include <iostream>
#include <thread>
#include <unistd.h>
// 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();
// 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();
// 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();
// 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);
}
{
// 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();
// 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);
}
{
// 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();
// 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);
}
{
// 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();
}
}