Author: @Xuandong Wong
For reprinting, please indicate the origin of the original text: http://aigo.iteye.com/blog/2296462
key world: std::shared_mutex, std::mutex, performance, benchmark, performance testing
Shared_mutex has a special application scenario: one or more read threads can read the shared resource at the same time, and only one write thread can modify the resource. In this case, performance advantage can be obtained from shared_mutex.
cppreference document
http://en.cppreference.com/w/cpp/thread/shared_mutex
Shared mutexes are usually used in situations when multiple readers can access the same resource at the same time without causing data races, but only one writer can do so.
Test code:
Note that the first version of VC that supports shared_mutex is VS2015 Update 2
/************************************************************************/ /* std::shared_mutex Performance comparison with std::mutex */ /************************************************************************/ #pragma once #define WRITE_THREAD_COUNT 8 #define LOOP_COUNT 5000000 #include <iostream> #include <mutex> // For std::unique_lock #include <shared_mutex> #include <thread> class shared_mutex_counter { public: shared_mutex_counter() = default; // Multiple threads/readers can read the counter's value at the same time. unsigned int get() const { std::shared_lock<std::shared_mutex> lock(mutex_); return value_; } // Only one thread/writer can increment/write the counter's value. void increment() { std::unique_lock<std::shared_mutex> lock(mutex_); value_++; } // Only one thread/writer can reset/write the counter's value. void reset() { std::unique_lock<std::shared_mutex> lock(mutex_); value_ = 0; } private: mutable std::shared_mutex mutex_; unsigned int value_ = 0; }; class mutex_counter { public: mutex_counter() = default; unsigned int get() const { std::unique_lock<std::mutex> lk(mutex_); return value_; } void increment() { std::unique_lock<std::mutex> lk(mutex_); value_++; } private: mutable std::mutex mutex_; unsigned int value_ = 0; }; void test_shared_mutex() { shared_mutex_counter counter; int temp; auto writer = [&counter]() { for (int i = 0; i < LOOP_COUNT; i++) { counter.increment(); } }; auto reader = [&counter, &temp]() { for (int i = 0; i < LOOP_COUNT; i++) { temp = counter.get(); } }; std::thread** tarray = new std::thread*[WRITE_THREAD_COUNT]; clock_t start = clock(); for (int i = 0; i < WRITE_THREAD_COUNT; i++) { tarray[i] = new std::thread(reader); } std::thread tw(writer); for (int i = 0; i < WRITE_THREAD_COUNT; i++) { tarray[i]->join(); } tw.join(); clock_t end = clock(); printf("[test_shared_mutex]\n"); printf("thread count:%d\n", WRITE_THREAD_COUNT); printf("result:%d cost:%dms temp:%d \n", counter.get(), end - start, temp); } void test_mutex() { mutex_counter counter; int temp; auto writer = [&counter]() { for (int i = 0; i < LOOP_COUNT; i++) { counter.increment(); } }; auto reader = [&counter, &temp]() { for (int i = 0; i < LOOP_COUNT; i++) { temp = counter.get(); } }; std::thread** tarray = new std::thread*[WRITE_THREAD_COUNT]; clock_t start = clock(); for (int i = 0; i < WRITE_THREAD_COUNT; i++) { tarray[i] = new std::thread(reader); } std::thread tw(writer); for (int i = 0; i < WRITE_THREAD_COUNT; i++) { tarray[i]->join(); } tw.join(); clock_t end = clock(); printf("[test_mutex]\n"); printf("thread count:%d\n", WRITE_THREAD_COUNT); printf("result:%d cost:%dms temp:%d \n", counter.get(), end - start, temp); } int main() { //In order to eliminate the irrelevant factors of the test program, only one is opened during the test. //test_shared_mutex(); test_mutex(); }
Test results:
2 Thread preemption
[test_mutex]
thread count:2
result:10000000 cost:1348ms temp:10000000
[test_shared_mutex]
thread count:2
result:10000000 cost:699ms temp:10000000
4-thread preemption
[test_mutex]
thread count:4
result:10000000 cost:2448ms temp:10000000
[test_shared_mutex]
thread count:4
result:10000000 cost:1233ms temp:10000000
8-thread preemption
[test_mutex]
thread count:8
result:5000000 cost:2452ms temp:5000000
[test_shared_mutex]
thread count:8
result:5000000 cost:1123ms temp:3231860
Conclusion:
In the case of multiple read-only threads and one write thread, shared_mutex is twice as fast as mutex.
PS: std::shared_mutex and std::mutex correspond to ReentrantReadWriteLock and ReentrantLock in java respectively.