Superlokkus
Superlokkus

Reputation: 5039

Implications std::mutex unlock synchronizes with lock to reacquiring

After answering this question, one thing bugged me again and made me nuts:

If a thread_1 is currently trying to lock a mutex and another thread_2 unlocks this mutex, is there a guarantee, that thread_1 will get the mutex, before thread_2 could try to lock it again.

To ensure the currently trying to lock, I assume that std::condition_variable::wait has a equivalent part to std::mutex::lock and is not just a while(try_lock())

I assume the answer is no, because of the varying scheduling std::mutex implementations. But I'm not sure and try to not be a reputation whore but,

  1. This question didn't had the currently trying to lock
  2. This question clarified the unlock/lock synchronizes with part but nothing about this general problem

I just want to be sure. Maybe I got paranoid.

Demonstration-Code:

#include <thread>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <cassert>

std::mutex lock; 
std::condition_variable ensure_in_lock;
std::atomic<int> invariant = 1;

void thread_1(){
    while (true){
        std::unique_lock<std::mutex> ul(lock);
        invariant++;
        ensure_in_lock.wait(ul);
        invariant++;
    }
}

void thread_2(){
    while (true){
        lock.lock();
        assert(invariant > 0); //<- This should be, in theory, able to break, shouldn't it?!
        ensure_in_lock.notify_all();
        lock.unlock();
        invariant--;
    }
}

int main(void)
{
    std::thread t1(thread_1);
    /*
    //make sure t1 really had started like with thread_once or pratically with this
    std::this_thread::sleep_for(std::chrono::seconds(1));
    */
    std::thread t2(thread_2);

    while (true);
    return 0;
}

Upvotes: 0

Views: 98

Answers (1)

David Schwartz
David Schwartz

Reputation: 182763

If a thread_1 is currently trying to lock a mutex and another thread_2 unlocks this mutex, is there a guarantee, that thread_1 will get the mutex, before thread_2 could try to lock it again.

Not only is there no guarantee, but such a guarantee would mandate a maximally terrible implementation, maximizing context switches rather than minimizing them. If a thread can keep going, you want to let it keep going and use up its timeslice. You don't want to keep switching between two threads letting each thread make a tiny increment of progress.

One of the benefits of locks is that they tend to deschedule contending threads, allowing threads to run for longer periods without suffering performance loss due to contention. Such an interleaving requirement would negate this benefit.

Upvotes: 2

Related Questions