olha
olha

Reputation: 2272

std::unique_lock move semantic

Please help me check if my understanding of std::unique_lock move semantic is correct.
Let's say I have a function myFunc which needs to acquire a mutex at the beginning of its execution.
This function is called from different functions, some of them e.g. myWrapper1 hold the same mutex before myFunc call.
Sometimes I need this lock not be released when myFunc's scope exits.

typedef std::unique_lock<std::mutex> MyLock;
class Example2
{
    std::mutex m_data_mutex;

    MyLock&& myFunc(MyLock&& lk)
    {
        bool was_lock = lk.owns_lock();
        if( !was_lock ) lk.lock();

        std::cout << "myFunc" << std::endl;

        if( !was_lock ) lk.unlock();
        return std::move(lk);
    }

    void myWrapper1()
    {
        MyLock lk(m_data_mutex);
        std::cout << "1" << std::endl;
        lk = myFunc(std::move(lk));
        std::cout << "2" << std::endl;
    }

    void myWrapper2()
    {
        MyLock lk(m_data_mutex);
        std::cout << "1" << std::endl;
        lk.unlock();
        lk = myFunc(std::move(lk));
        std::cout << "2" << std::endl;
        lk.lock();
        std::cout << "3" << std::endl;
    }
};

So the questions are:

  1. for myWrapper1 there's a guarantee that MyLock will be released only at the end of myWrapper1 scope, isn't it?
  2. Do I use a correct idiom for this problem?

Upvotes: 2

Views: 1017

Answers (1)

Solomon Slow
Solomon Slow

Reputation: 27190

Is there some reason why you can't do something like this instead? IMO, it's a lot more clean than moving locks around from owner to owner.

std::mutex my_lock;

void myFunc_locked() {
    ...do something that requires my_lock to be locked...
}

void myFunc() {
    std::lock_guard<std::mutex> guard(my_lock);
    myFunc_locked();
}

void myWrapper1() {
    std::lock_guard<std::mutex> guard(my_lock);
    ...do something else that requires my_lock to be locked...
    myFunc_locked();
}

void myWrapper2() {
    ...
    myFunc();
}

Or, do as @Nevin suggested. Maybe cleaner still:

std::mutex my_lock;

void myFunc(std::lock_guard<std::mutex>> const& guard) {
    ...do something that requires my_lock to be locked...
}

void myFunc() {
    std::lock_guard<std::mutex> guard(my_lock);
    myFunc(guard);
}

void myWrapper1() {
    std::lock_guard<std::mutex> guard(my_lock);
    ...do something else that requires my_lock to be locked...
    myFunc(guard);
}

void myWrapper2() {
    ...
    myFunc();
}

Upvotes: 2

Related Questions