Strategies for lock classes std::try_to_lock, std::adopt_lock, std::defer_lock

suggest change

When creating a std::unique_lock, there are three different locking strategies to choose from: std::try_to_lock, std::defer_lock and std::adopt_lock

  1. std::try_to_lock allows for trying a lock without blocking:
{
    std::atomic_int temp {0};
    std::mutex _mutex;
    
    std::thread t( [&](){
        
        while( temp!= -1){
            std::this_thread::sleep_for(std::chrono::seconds(5));
            std::unique_lock<std::mutex> lock( _mutex, std::try_to_lock);
            
            if(lock.owns_lock()){
                //do something
                temp=0;
            }
        }
    });
    
    while ( true )
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::unique_lock<std::mutex> lock( _mutex, std::try_to_lock);
        if(lock.owns_lock()){
            if (temp < INT_MAX){
                ++temp;
            }
            std::cout << temp << std::endl;
        }
    }
}
  1. std::defer_lock allows for creating a lock structure without acquiring the lock. When locking more than one mutex, there is a window of opportunity for a deadlock if two function callers try to acquire the locks at the same time:
{
    std::unique_lock<std::mutex> lock1(_mutex1, std::defer_lock);
    std::unique_lock<std::mutex> lock2(_mutex2, std::defer_lock);
    lock1.lock()
    lock2.lock(); // deadlock here
    std::cout << "Locked! << std::endl;
    //...
}

With the following code, whatever happens in the function, the locks are acquired and released in appropriate order:

{
    std::unique_lock<std::mutex> lock1(_mutex1, std::defer_lock);
    std::unique_lock<std::mutex> lock2(_mutex2, std::defer_lock);
    std::lock(lock1,lock2); // no deadlock possible
    std::cout << "Locked! << std::endl;
    //...
    
}
  1. std::adopt_lock does not attempt to lock a second time if the calling thread currently owns the lock.
{
    std::unique_lock<std::mutex> lock1(_mutex1, std::adopt_lock);
    std::unique_lock<std::mutex> lock2(_mutex2, std::adopt_lock);
    std::cout << "Locked! << std::endl;
    //...
}

Something to keep in mind is that std::adopt_lock is not a substitute for recursive mutex usage. When the lock goes out of scope the mutex is released.

Feedback about page:

Feedback:
Optional: your email if you want me to get back to you:


Mutexes:
* Strategies for lock classes std::try_to_lock, std::adopt_lock, std::defer_lock

Table Of Contents
8 Arrays
11 Loops
39 Streams
51 Unions
56 Lambdas
60 SFINAE
62 RAII
67 Sorting
84 RTTI
87 Scopes
104 Profiling
107 Recursion
117 Iteration
125 Alignment
134 Semaphore
136 Debugging
139 Mutexes
142 decltype