C++ Concurrency Sandbox
Loading...
Searching...
No Matches
ReaderWriterLock.cpp
Go to the documentation of this file.
1/**
2 * @file ReaderWriterLock.cpp
3 * @brief Demonstration of Thread-Safe Data Access using Readers-Writers Lock.
4 * * This file illustrates the use of std::shared_mutex to allow multiple threads
5 * to read data simultaneously while ensuring that writing is an exclusive operation.
6 */
7
8#include <iostream>
9#include <chrono>
10#include <thread>
11#include <shared_mutex>
12#include <vector>
13#include <mutex>
14
15/** * @brief Global mutex to prevent console output interleaving.
16 * * Standard output (std::cout) is not inherently thread-safe for atomic operations.
17 * This mutex ensures that logs from different threads do not garble each other.
18 */
19std::mutex log_mtx;
20
21/**
22 * @class SharedMetaData
23 * @brief Manages a shared resource with high-concurrency read access.
24 * * Uses std::shared_mutex to solve the Readers-Writers problem.
25 * - **Readers** use std::shared_lock (shared ownership).
26 * - **Writers** use std::unique_lock (exclusive ownership).
27 */
29private:
30 std::shared_mutex rw_mutex; ///< The core R/W lock allowing multiple readers or one writer.
31 int shared_resource = 0; ///< The actual data being protected.
32
33public:
34 /**
35 * @brief Reads the shared data concurrently.
36 * * Multiple reader threads can execute this method at the same time,
37 * provided no writer holds an exclusive lock.
38 * * @param thread_id Unique identifier for the reader thread.
39 */
40 void read_data(int thread_id) {
41 // Acquire shared ownership
42 std::shared_lock<std::shared_mutex> reader_lock(rw_mutex);
43
44 {
45 // Thread-safe logging for the start of the read
46 std::lock_guard<std::mutex> log(log_mtx);
47 std::cout << "[Reader " << thread_id << "] Reading value: " << shared_resource << std::endl;
48 }
49
50 // Simulate a time-consuming read operation
51 std::this_thread::sleep_for(std::chrono::milliseconds(200));
52
53 {
54 // Thread-safe logging for the end of the read
55 std::lock_guard<std::mutex> log(log_mtx);
56 std::cout << "[Reader " << thread_id << "] Finished reading." << std::endl;
57 }
58 }
59
60 /**
61 * @brief Updates the shared data exclusively.
62 * * Blocks all incoming readers and waits for existing readers to finish
63 * before modifying the shared_resource.
64 * * @param thread_id Unique identifier for the writer thread.
65 * @param new_data The new value to store in the resource.
66 */
67 void write_data(int thread_id, int new_data) {
68 // Acquire exclusive ownership
69 std::unique_lock<std::shared_mutex> writer_lock(rw_mutex);
70
71 {
72 std::lock_guard<std::mutex> log(log_mtx);
73 std::cout << ">>> [Writer " << thread_id << "] Writing new value: " << new_data << " <<<" << std::endl;
74 }
75
76 shared_resource = new_data; // Update the resource
77
78 // Simulate a heavy write operation
79 std::this_thread::sleep_for(std::chrono::milliseconds(500));
80
81 {
82 std::lock_guard<std::mutex> log(log_mtx);
83 std::cout << ">>> [Writer " << thread_id << "] Write complete. <<<" << std::endl;
84 }
85 }
86};
87
88/**
89 * @brief Main execution logic.
90 * * Orchestrates a high-concurrency scenario in three phases:
91 * 1. Initial writer followed by a burst of 20 readers.
92 * 2. An interleaved writer that waits for the burst of readers to clear.
93 * 3. Subsequent bursts of readers (30 total) that must wait for the writer to finish.
94 */
95int main(void) {
96 SharedMetaData store;
97 std::vector<std::thread> threads;
98
99 // Phase 1 : Initial Write and High concurrency of readers
100 threads.emplace_back(&SharedMetaData::write_data, &store, 1, 99);
101 for(int i=0; i<=20; i++) {
102 threads.emplace_back(&SharedMetaData::read_data, &store, i);
103 }
104
105 // Phase 2 : Interleaving a writer
106 // This writer will wait until all active readers from Phase 1 finish their 200ms sleep.
107 std::this_thread::sleep_for(std::chrono::milliseconds(700));
108 threads.emplace_back(&SharedMetaData::write_data, &store, 2, 234);
109
110 // Phase 3 : Post-write readers
111 // These readers will block until Writer 2 releases the unique_lock.
112 for(int i=21; i<=30; i++) {
113 threads.emplace_back(&SharedMetaData::read_data, &store, i);
114 }
115
116 for(int i=31; i<=40; i++) {
117 threads.emplace_back(&SharedMetaData::read_data, &store, i);
118 }
119
120 for(int i=41; i<=50; i++) {
121 threads.emplace_back(&SharedMetaData::read_data, &store, i);
122 }
123
124 // Join all threads to ensure clean termination
125 for(auto& t : threads) {
126 if(t.joinable())
127 t.join();
128 }
129
130 return 0;
131}
std::mutex log_mtx
Global mutex to prevent console output interleaving.
int main(void)
Main execution logic.
Manages a shared resource with high-concurrency read access.
void read_data(int thread_id)
Reads the shared data concurrently.
void write_data(int thread_id, int new_data)
Updates the shared data exclusively.