C++ 11 feature: C++ Multithreading Tutorial: Unique Lock in C++ threading

In the previous chapter we saw lock_guard. In this chapter we shall learn unique lock.

Unique lock is a class that is available form C++ 11.

Unique lock is a wrapper over a mutex. It will own the mutex that is passed to unique lock.

A unique lock has below features:

1. A unique lock can have different locking strategies.
2. Time based locking are available [try_lock_for, try_lock_until].
3. Recursive locking is also available.
4. Transfer of lock ownership using move.
5. It has also support for conditional variables.

Below are some of the locking strategies available in unique lock.

1. defer_lock: It will not acquire ownership of mutex.
2. try_to_lock: It will try acquire ownership of mutex without blocking.
3. adopt_lock: It will assume that the calling thread has already acquire ownership of mutex.

When you don’t specify the locking strategy, it will just lock the mutex.

One important point to remember about unique_lock is that, it will automatically unlock the mutex, when it goes out of scope.

Now lets understand unique_lock with help of examples:

Example 1: A simple unique_lock

#include <iostream>       // std::cout
#include <chrono>         // std::chrono::milliseconds
#include <thread>         // std::thread
#include <mutex>          // std::timed_mutex

// for more tutorials on C, C++, DS visit www.ProDeveloperTutorial.com

using namespace std;

std::mutex mtx;

int count_num = 0;


void increment_fun (int thread_num, int val) 
{
   
    unique_lock<mutex> lock(mtx); // locking mtx mutex 

    for (int i = 0; i < val; ++i)
    {
        cout<<"Thread "<<thread_num<<" count = "<<count_num++<<endl;
    }
    //mtx.unlock();// no need to call unlock
}

int main ()
{
    std::thread t1 (increment_fun, 1, 5);
    std::thread t2 (increment_fun, 2, 6);
    
    t1.join();
    t2.join();
    

  return 0;
}

Output:

Thread 1 count = 0
Thread 1 count = 1
Thread 1 count = 2
Thread 1 count = 3
Thread 1 count = 4
Thread 2 count = 5
Thread 2 count = 6
Thread 2 count = 7
Thread 2 count = 8
Thread 2 count = 9
Thread 2 count = 10

Example 2: unique_lock with defer_lock flag

#include <iostream>       // std::cout
#include <chrono>         // std::chrono::milliseconds
#include <thread>         // std::thread
#include <mutex>          // std::timed_mutex

// for more tutorials on C, C++, DS visit www.ProDeveloperTutorial.com

using namespace std;

std::mutex mtx;

int count_num = 0;


void increment_fun (int thread_num, int val) 
{
    // as we are using defer_lock flag, it will not lock the mutex "mtx"
    unique_lock<mutex> lock(mtx, defer_lock);

    //hence you explicitly need to call the lock on the mutex
    lock.lock();

    for (int i = 0; i < val; ++i)
    {
        cout<<"Thread "<<thread_num<<" count = "<<count_num++<<endl;
    }
    //mtx.unlock();// no need to call unlock, as we are using unique_lock
}

int main ()
{
    std::thread t1 (increment_fun, 1, 5);
    std::thread t2 (increment_fun, 2, 6);
    
    t1.join();
    t2.join();
    

  return 0;
}

Output:

Thread 1 count = 0
Thread 1 count = 1
Thread 1 count = 2
Thread 1 count = 3
Thread 1 count = 4
Thread 2 count = 5
Thread 2 count = 6
Thread 2 count = 7
Thread 2 count = 8
Thread 2 count = 9
Thread 2 count = 10

 

 

Write a Comment

Leave a Comment

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