Reputation: 8182
I was wondering. When I use a std::mutex _lock
and want to rely on guards to release it, can I use it like this?
class MyClass{
private:
mutable std::mutex _lock;
void subroutine(){/*...*/}
public:
void foo(){
std::lock(_lock);std::lock_guard<std::mutex> g(_lock, std::adopt_lock);
subroutine();
//require I still have the lock here
//...
return; //g goes out of scope ==> _lock is released
}
};
Or would the call to subroutine
already cause the lock to be released? If the latter turns out to be the case, what are my options?
Update
What about this case?
class MyClass{
private:
mutable std::mutex _lock;
public:
void subroutine(){ //can be called on its own
std::lock(_lock);std::lock_guard<std::mutex> g(_lock, std::adopt_lock);
/*...*/
}
void foo(){
std::lock(_lock);std::lock_guard<std::mutex> g(_lock, std::adopt_lock);
subroutine();
//require I still have the lock here
//...
return; //g goes out of scope ==> _lock is released
}
};
Upvotes: 0
Views: 2084
Reputation: 2890
The call to subroutine would not cause the lock to be released. The thread's lock on _lock is released when the std::lock_guard object goes out of scope (as you mention in your comment).
void foo(){
std::lock_guard<std::mutex> lg{_lock}; // lock the mutex
subroutine(); // lock is held here during this call
// so subroutine must not attempt to lock the mutex _lock!
return; // lg goes out of scope => its destructor is called which releases the lock on _lock
}
To answer your second question, you have a problem when foo acquires a lock on _lock and then calls subroutine, which again tries to lock _lock. A thread cannot acquire a lock on a mutex on which it already holds a lock. I would re-think your class design. If you absolutely must have this design you could do something like
void subroutine(bool called_from_foo = false)
{
if(!called_from_foo)
std::lock_guard<std::mutex> lg{_lock};
/* ... */
}
void foo()
{
std::lock_guard<std::mutex> lg{_lock};
subroutine(true);
/* ... */
return;
}
Although I would not recommend this because it would be easy to use subroutine in a wrong way, causing undefined behavior in your program.
If you find yourself having to pass the owner of a lock between functions I would take a look at std::unique_lock, because this type is moveable.
Upvotes: 1