C++ 11 feature: C++ Multithreading Tutorial: Timed mutex in C++ threading

In the previous chapters we learnt about Mutex, Race condition and critical section. In this chapter we shall learn about timed mutex.

Generally in a mutex, when one thread tries to acquires a lock [T2], that has already been locked by another thread [T1], current thread [T2] will wait for a period of time till it is unlocked.

So the time that the thread T2 waits is time wasted. And we also dont know then T1 thread will release the lock? It might release in 2 min or 2 hours.

To solve this problem we have try_lock. But the problem with try_lock is that, it will try to acquire the lock, if it is not available, then it will return false, and continue to process other work.

But we want to wait for certain period of time to check if the lock has been released.

Hence to solve this problem we have “timed mutex” in C++.

In timed mutex, we will wait till timeout_time or till the lock is acquired within the timeout_time period. If the lock is not acquired and timeout occurs, then we return false.

Timed mutex is a class present in “std” namespace.

class timed_mutex; //(since C++11)

Member functions available in timed mutex:

lock : Used to lock the mutex.

try_lock: tries to lock the mutex.

try_lock_for: Tries to lock till timeout occurs

try_lock_until: Tries to lock till specified amount of time.

unlock: Used to unlock the mutex.

In this tutorial we shall see try_lock_for() and try_lock_until().

try_lock_for() example:

When you use try_lock_for() to lock a mutex, then the second thread [T2] will wait for that amount of time for the first thread [T1] to be unlocked. If it reaches the T2 thread reaches the timeout, then it will simply return.

This behavior can be found in below example:

In the program below, we are trying to increment a value. When the first thread enters and acquires the lock, it will sleep for 3 seconds.

Now the 2nd thread comes and tries to acquires the lock. Now as we have used try_lock_for(), it will wait for 2 seconds to unlock the section.

As the thread 1 is sleeping for 3 seconds, time out will occur for thread 2, then it will not be able to acquire the lock.

The output will confirm the same.

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

// for more tutorials visit www.ProDeveloperTutorial.com

using namespace std;

std::timed_mutex mtx;

int count_num = 0;

void update_value (int i) 
{
    //created a try_lock_for mutex
    if(mtx.try_lock_for(std::chrono::seconds(2)))
    {
        count_num ++;
        std::this_thread::sleep_for(std::chrono::seconds(3));
        cout<<"Thread " << i << " acquired lock"<<endl;
        mtx.unlock();
    }
    else
    {
        cout<<"Thread " << i << " was not able to acquire lock"<<endl;

    }

}

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

  return 0;
}

Output:

Thread 2 was not able to acquire lock
Thread 1 acquired lock

If you change the try_lock_for() for 4 seconds, thread 2 will also be acquire the lock. Then the output will be as below:

After changing the timeout period for 4 seconds, below is the output:

Thread 2 acquired lock
Thread 1 acquired lock

try_lock_until() example:

In try_lock_until(), we wait from current time till the time mentioned. If the timeout occurs it will return false.

In the below example, we are waiting 2 seconds from the current time.

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

// for more tutorials visit www.ProDeveloperTutorial.com

using namespace std;

std::timed_mutex mtx;

int count_num = 0;

void update_value (int i) 
{
    auto now=std::chrono::steady_clock::now();

    //created a try_lock_until mutex
    if(mtx.try_lock_until(now + std::chrono::seconds(2)))
    {
        count_num ++;
        std::this_thread::sleep_for(std::chrono::seconds(1));
        cout<<"Thread " << i << " acquired lock"<<endl;
        mtx.unlock();
    }
    else
    {
        cout<<"Thread " << i << " was not able to acquire lock"<<endl;

    }

}

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

  return 0;
}

Output:

Thread 1 acquired lock
Thread 2 acquired lock
Write a Comment

Leave a Comment

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