I wanted to see the performance comparison of std::lock_guard versus the std::unique_lock. Even though they both provide slightly different implementations and abilities, the performance impact is worth investigating. So, I wrote the following and tested it on my MacBook Air:
#include <iostream>
#include <mutex>
#include <cassert>
#include <chrono>
std::mutex aMutex; // setup a mutex for use
void usingLockGuard() {
// std::lock_guard locks the mutex and
// unlocks at the end of the function
// the lock on the mutex is guaranteed
std::lock_guard aLock(aMutex);
int sum = 0;
for(int i = 0; i < 100; ++i) {
sum += i;
}
}
void usingUniqueLock() {
// std::unique_lock locks the mutex and
// unlocks at the end of the function
std::unique_lock aLock(aMutex);
// the lock on the mutex is not always guaranteed
assert(aLock.owns_lock());
int sum = 0;
for(int i = 0; i < 100; ++i) {
sum += i;
}
}
int main(int argc, const char * argv[]) {
// lock guard
std::chrono::high_resolution_clock::time_point startTime1 =
std::chrono::high_resolution_clock::now();
for(int i = 0; i < 100000; ++i) {
usingLockGuard();
}
std::chrono::high_resolution_clock::time_point endTime1 =
std::chrono::high_resolution_clock::now();
auto elapsedTime1 = std::chrono::duration_cast(endTime1 - startTime1).count();
std::cout << "std::lock_guard elapsed time: "
<< elapsedTime1 << " microseconds" << std::endl;
// unique lock
std::chrono::high_resolution_clock::time_point startTime2 =
std::chrono::high_resolution_clock::now();
for(int j = 0; j < 100000; ++j) {
usingUniqueLock();
}
std::chrono::high_resolution_clock::time_point endTime2 =
std::chrono::high_resolution_clock::now();
auto elapsedTime2 = std::chrono::duration_cast(endTime2 - startTime2).count();
std::cout << "std::unique_lock elapsed time: "
<< elapsedTime2 << " microseconds " << std::endl;
return 0;
}
Here are the typical results:
std::lock_guard elapsed time: 29400 microseconds std::unique_lock elapsed time: 29459 microseconds
So, on average the performance of unique_lock is comparable in my experience to lock_guard. Although, there is some additional overhead expected with unique_lock, but I haven’t noticed it in the above experiment. YMMV.
