lock_guard and unique_lock

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.

Leave a Reply

Your email address will not be published. Required fields are marked *