In C++, std::mutex is a mechanism that locks access to the shared resource when some other thread is working on it so that errors such as race conditions can be avoided and threads can be synchronized. But in some cases, several threads need to read the data from shared resources at the same time. Here, the std::shared_mutex comes into play. In this article, we will discuss the std::shared_mutex, its associated methods, and how it is different from the std::mutex in C++.
Prerequisite: C++ Multithreading, std::mutex in C++.
std::shared_mutex in C++
In C++, std::shared_mutex is a synchronization primitive that lets several threads use a shared resource simultaneously for reading while guaranteeing exclusive writing access. It is helpful in situations where many threads need read-only access to the same data structure, but write operations aren't often used.
Types of Locks in std::shared_mutex
The std::shared_mutex provides two types of locks:
- Unique Lock: It is a unique lock that can only be acquired by a single thread at a time. This lock only allows a single thread to modify the shared resources while blocking the other threads. It is similar to the lock provided by the std::mutex.
Exclusive Lock in C++- Shared Lock: The shared lock is a non-exclusive lock that several threads can acquire at once. This gives multiple threads read-only access to the shared resource.
Shared Lock in C++
Note: Multiple threads can aquire the shared lock simultaneously but only one thread can aquire the exclusive lock at a time.
Methods Associated with std::shared_mutex
The std::shared_mutex contains several member methods that are required to perform different operations. Some of the commonly used functions are:
S. No.
| Function
| Description
|
---|
1
| lock() | Exclusively locks the mutex and blocks if it fails. |
---|
2
| unlock() | Unlock the exclusive lock. |
---|
3
| try_lock() | Tries to uniquely lock the mutex. This function doesn't block and returns false if the mutex is already locked for exclusive access. |
---|
4
| lock_shared() | Gets the mutex to use a shared lock. |
---|
5
| unlock_shared() | Unlocks the shared lock for the current thread. |
---|
6
| try_lock_shared() | Tries for shared lock. This function doesn't block and returns false if fails. |
---|
Example of std::shared_lock
C++
// C++ program to illustrate the use of shared_mutex
#include <iostream>
#include <shared_mutex>
#include <mutex>
#include <thread>
using namespace std;
// creating a shared_mutex object
shared_mutex mutx;
int shared_data = 11;
// callable with shared lock
void readData() {
shared_lock<shared_mutex> lock(mutx);
cout << "Thread " << this_thread::get_id() << ": ";
cout << shared_data << endl;
}
// callable with unique_lock
void writeData(int n) {
unique_lock<shared_mutex> lock(mutx);
shared_data = n;
cout << "Thread" << this_thread::get_id() << ": \n";
}
// driver code
int main()
{
thread t1(readData);
thread t2(writeData, 128);
thread t3(writeData, 10);
thread t4 (readData);
t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}
Output
Read Thread 140122977658432: 11
Write Thread 140122960873024
Write Thread 140122969265728
Read Thread 140122952480320: 128
std::shared_mutex vs std::mutex
Similar to std::mutex, std::shared_mutex is a synchronization primitive that prevents concurrent access to shared resources. Both have their own advantages and disadvantages.
Advantages of std::shared_mutex over std::mutex
The std::shared_mutex has the following advantages over std::mutex:
- Enhanced Parallelism: Multiple threads can access the shared data for reading operation at once enhancing the parallelism of the program where only read operation is required.
Advantages of std::shared_mutex over std::mutex
- Limited Flexibility: There are only two types of locks that the std::shared_mutex supports: shared locks and unique locks. Additional lock types, such as recursive and postponed locks, are supported via the std::mutex.
- Increased Complexity: Compared to std::mutex, std::shared_mutex has greater complexity. It may become more challenging to understand and apply.
Applications
Following are some main applications of std::shared_mutex:
- When reading data is the primary operation and writing data is uncommon, shared mutexes offer effective parallelism.
- Shared mutexes can be used in caching algorithms to enable simultaneous updating of the cache by one thread while allowing several threads to read data that has been cached.
- Database connection pooling allows for simultaneous reading and updating of connection information by several threads, but not for simultaneous modification.
Conclusion
std::shared_mutex is one of the useful mechanisms for access synchronization in multithreaded environments. It works especially effectively in scenarios where the shared data is mostly read-only. But before utilizing the std::shared_mutex, it's crucial to be aware of its limitations.
Similar Reads
std::make_shared in C++
In C++, std::make_shared() is a function that returns a shared pointer to the object of specific type after dynamically creating it. It offers a safer and more efficient way to create shared pointers, reducing the chances of errors and improving performance. The function is declared in the <memor
3 min read
shared_ptr in C++
std::shared_ptr is one of the smart pointers introduced in C++11. Unlike a simple pointer, it has an associated control block that keeps track of the reference count for the managed object. This reference count is shared among all the copies of the shared_ptr instances pointing to the same object, e
5 min read
Mutex in C++
Mutex stands for Mutual Exclusion. In C++, std::mutex class is a synchronization primitive that is used to protect the shared data from being accessed by multiple threads simultaneously. The shared data can be in the form of variables, data structures, etc. std::mutex class implements mutex in C++.
4 min read
std::promise in C++
In C++ multithreading, a thread is the basic unit that can be executed within a process and to communicate two or more threads with each other, std::promise in conjunction with std::future can be used. In this article, we will discuss the std::promise in C++ and how to use it in our program. What is
3 min read
What is a Shared Memory?
Shared Memory is a concept of Operating Systems and is mainly used in Inter-process Communication. If two processes want to share data with each other, they need some intermediate medium to do so and this is where shared memory comes into the picture. What is a Shared Memory?Every process has a dedi
4 min read
Iterators in C++ STL
An iterator in C++ is a pointer-like object that points to an element of the STL container. They are generally used to loop through the contents of the STL container in C++. The main advantage of STL iterators is that they make the STL algorithms independent of the type of container used. We can jus
11 min read
unordered_multiset reserve() in C++ STL
The reserve() function of unordered_multiset sets the number of buckets in the container (bucket_count) to the most appropriate to contain at least n elements. If n is greater than the current bucket_count multiplied by the max_load_factor, the container's bucket_count is increased and a rehash is f
2 min read
std::set_intersection in C++
The intersection of two sets is formed only by the elements that are present in both sets. The elements copied by the function come always from the first range, in the same order. The elements in the both the ranges shall already be ordered.Examples: Input : 5 10 15 20 25 50 40 30 20 10 Output : The
5 min read
Multithreading in C++
Multithreading is a technique where a program is divided into smaller units of execution called threads. Each thread runs independently but shares resources like memory, allowing tasks to be performed simultaneously. This helps improve performance by utilizing multiple CPU cores efficiently. Multith
6 min read
Namespace in C++
Name conflicts in C++ happen when different parts of a program use the same name for variables, functions, or classes, causing confusion for the compiler. To avoid this, C++ introduce namespace. Namespace is a feature that provides a way to group related identifiers such as variables, functions, and
7 min read