Potential deadlock in thread-safe stack C++ - c++

In the book "Concurrency in Action", there's an implementation of thread-safe stack where mutex is acquired/locked upon entering pop() and empty() functions like shown below:
class threadsafe_stack {
private:
std::stack<T> data;
mutable std::mutex m;
public:
//...
void pop(T& value) {
std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw empty_stack();
value = std::move(data.top());
data.pop();
}
bool empty() const {
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
};
My question is, how does this code not run into a deadlock, when a thread, that has acquired the lock upon entering pop() is calling empty() which is protected by mutex as well? If lock() is called by the thread that already owns the mutex, isn't that undefined behavior?

how does this code not run into a deadlock, when a thread, that has acquired the lock upon entering pop() is calling empty() which is protected by mutex as well?
Because you are not calling empty member function of threadsafe_stack but you are calling empty() of class std::stack<T>. If the code would be:
void pop(T& value)
{
std::lock_guard<std::mutex> lock(m);
if(empty()) // instead of data.empty()
throw empty_stack();
value = std::move(data.top());
data.pop();
}
Then, it would be undefined behavior:
If lock is called by a thread that already owns the mutex, the behavior is undefined: for example, the program may deadlock. An implementation that can detect the invalid usage is encouraged to throw a std::system_error with error condition resource_deadlock_would_occur instead of deadlocking.
Learn about recursive and shared mutex.

Not 100% sure what you mean, I guess you mean calling pop and empty sequentially in the same thread? Like in
while(!x.empty()) x.pop();
std::lock_guard follows RAII. This means the constructor
std::lock_guard<std::mutex> lock(m);
will acquire/lock the mutex and the destructor (when lock goes out of scope) will release/unlock the mutex again. So it's unlocked at the next function call.
Inside pop only data.empty() is called, which is not protected by a mutex. Calling this->empty() inside pop would indeed result in undefined behaviour.

You would be correct if pop would call this->empty. Locking the same mutex twice via a std::lock_guard is undefined behavior unless the locked mutex is a recursive one.
From cppreference on the constructor (the one that is used in the example code):
Effectively calls m.lock(). The behavior is undefined if m is not a recursive mutex and the current thread already owns m.
For the sake of completeness, there is a second constructor:
lock_guard( mutex_type& m, std::adopt_lock_t t );
which
Acquires ownership of the mutex m without attempting to lock it. The behavior is undefined if the current thread does not own m.
However, pop calls data.empty and this is the method of the private member, not the member function empty of threadsafe_stack. There is no problem in the code.

Related

Why does this code not cause a dead-lock?

I have below code where function bar lock the mutex and then called function foo, however function foo lock the same mutex. according to my understanding, dead-lock will take place because foo are trying to lock the same mutex and it has been locked in function bar. But below code executes without any halt. Who knows the reason??
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void foo()
{
pthread_mutex_lock(&mutex);
cout<<"excuting foo!!"<<endl;
pthread_mutex_unlock(&mutex);
}
void bar()
{
pthread_mutex_lock(&mutex);
cout<<"excuting bar!!"<<endl;
foo();
pthread_mutex_unlock(&mutex);
}
int main()
{
bar();
}
The POSIX thread specification allows a POSIX thread implementation to use any of the standard three mutex types as the default one:
If the mutex type is PTHREAD_MUTEX_DEFAULT, the behavior of
pthread_mutex_lock() may correspond to one of the three other standard
mutex types
What is PTHREAD_MUTEX_DEFAULT? That's pretty much what you expect:
The default value of the type attribute is PTHREAD_MUTEX_DEFAULT.
...
An implementation may map PTHREAD_MUTEX_DEFAULT to one of the other
mutex types.
You are expecting your mutex to be PTHREAD_MUTEX_NORMAL which will cause a deadlock here. However, your particular thread implementation appears to be the PTHREAD_MUTEX_RECURSIVE type, which can be locked more than once by the same process. This is the behavior you are observing.
You need to modify bar() as:
void bar()
{
pthread_mutex_lock(&mutex);
cout<<"excuting bar!!"<<endl;
pthread_mutex_unlock(&mutex);
foo();
}
In your code, deadlock is there because sequence is following
1. bar () locks mutex,
2. Foo() trying to lock mutex again which is already locked by bar
3. bar() unlocks it,but earlier operation step 2, still waiting for mutex. This steps waits for step 2 to finish

How to avoid locking using lock_guard?

https://en.cppreference.com/w/cpp/thread/lock_guard
(constructor)
constructs a lock_guard, optionally locking the given mutex
What would be the way to avoid locking if it is optional?
This is one way to avoid having the lock_guard constructor lock the given mutex :
std::mutex mtx;
mtx.lock();
std::lock_guard<std::mutex> lck(mtx, std::adopt_lock);
The intention is to allow your lock_guard to take ownership of a mutex that you already locked.
From: https://en.cppreference.com/w/cpp/thread/lock_guard/lock_guard
explicit lock_guard( mutex_type& m ); (1) (since C++11)
lock_guard( mutex_type& m, std::adopt_lock_t t ); (2) (since C++11)
lock_guard( const lock_guard& ) = delete; (3) (since C++11)
Acquires ownership of the given mutex m.
1) Effectively calls m.lock(). The behavior is undefined if m is not a recursive mutex and the current thread already owns m.
2) Acquires ownership of the mutex m without attempting to lock it.
The behavior is undefined if the current thread does not own m.
3) Copy constructor is deleted.
The behavior is undefined if m is destroyed before the lock_guard object is.

Destructor and thread safety

I want to create a thread safe class containing a method to insert elements into a list.
When one of the threads destroys an instance, I want the messages in the list to be processed, while preventing other threads to insert other messages.
The idea is the following:
MyClass{
...
public:
...
void send(string s){
lock_guard<mutex> lock(m);
my_list.push_back(s);
}
~MyClass(){
lock_guard<mutex> lock(m);
for(string s:my_list)
process(s);
}
}
Is the synchronization correct?
For the method send I added the lock so that multiple threads can call it in a safe way.
As for what concerns the destructor, is there a possibility that a thread will call send between the lock release and the actual destruction of the instance? ie. is the for (and the following lock_guard destruction) the last instruction that will be executed before the actual destruction, or a race condition is possible once the destructor is executed?
You might split your class:
class MyClass
{
public:
void send(const std::string& s){
lock_guard<mutex> lock(m);
my_list.push_back(s);
}
void process_all_messages()
{
lock_guard<mutex> lock(m);
for (const string& s : my_list)
process(s);
//my_list.clear();
}
void process(const std::string& s);
// ... mutex, list, ...
};
And have a wrapper on it
class MyClassPerTHread
{
public:
explicit MyClassPerTHread(std::shared_ptr<MyClass> ptr) : ptr(ptr) {}
~MyClassPerTHread(){ ptr->process_all_messages(); }
// MyClassPerTHread(const MyClassPerTHread&);
// MyClassPerTHread(MyClassPerTHread&&);
// MyClassPerTHread& operator=(const MyClassPerTHread&);
// MyClassPerTHread& operator=(MyClassPerTHread&&);
void send(const std::string& s) { ptr->send(s); };
private:
std::shared_ptr<MyClass> ptr;
};
So in main, you create an instance of std::shared_ptr<MyClass>.
you pass it to each thread which wrap it in MyClassPerTHread.
When MyClassPerTHread is destroyed, You process the messages as expected.
You might want to adapt MyClassPerTHread for move/copy though.
You have a good intuition here; the lock_guard in the destructor isn't doing any good at all.
Here's why:
The way this is written, any calls to send() must be done before ~MyClass()'s lock_guard is created – otherwise the message won't get processed and send() could very well be using m and my_list after their destruction is complete, leading to undefined behavior. Callers of send() have no way to make sure this happens other than just making sure all calls to send() are done before ~MyClass() even starts.
This is OK. Most classes have (or should have) a requirement that clients serialize destruction. That is, clients must make sure all callers to send() are done before ~MyClass() is invoked. In fact, all standard library classes have this requirement, unless otherwise documented. Some classes deliberately don't require this; that's fine, but somewhat exotic.
This really isn't terribly hard for clients to do, fortunately; they can just use a shared_ptr or something, as suggested by Jarod42.
tl;dr:
is there a possibility that a thread will call send between the lock release and the actual destruction of the instance?
Yes! Document that it is a client error if they do this and get rid of the lock in the destructor.

Using mutex, lock_guard, unique_lock properly in a class

I'm trying to understand std::mutex, std::lock_guard, std::unique_lock better when working with a class.
For starters I sort of know the difference between lock_guard and unique_lock: I know that lock_guard only locks the mutex on construction which is a preferred use when using it in a class member function as such:
class Foo {
std::mutex myMutex;
public:
void someFunc() {
std::lock_guard<std::mutex> guard( myMutex );
// code
}
};
As in the above the lock_guard with the class's member myMutex will be locked in the beginning of the scope of the function Foo::someFunc() then unlocked after the code leaves the scope due to the destructors of both lock_guard and mutex.
I also understand that unique_lock allows you to lock & unlock a mutex multiple times.
My question is about a design of a class to where; what If I want the mutex to be locked in the constructor of the class, then not to have it unlock when the constructor goes out of scope, but to unlock when the destructor of the class is called...
class Foo {
std::mutex myMutex;
public:
Foo() {
// lock mutex here;
}
~Foo() {
// unlock mutex here;
}
};
Can the above be achieved; and if so how?
In the last example above what I'm not sure about is: if a lock_guard is used in the constructor of the class; will it go out of scope after the constructor leaves scope, or when the class's destructor is invoked when the object of the class goes out of scope? I like to try to mimic the desired behavior of the 2nd example shown.
After I had posted this question: I did a little more research and some trial and errors. With that I have opted towards a different implementation and solution.
Instead of what I was originally proposing, I ended up using std::shared_mutex and std:shared_lock.
So in my class's header I'm not saving or storing any mutex. Now in my class's cpp file. I'm using a static global shared_mutex
So my class now looks like this:
Foo.cpp
#include "Foo.h"
#include <mutex>
std::mutex g_mutex;
Foo::Foo() {
// code not locked
{ // scope of guard
std::lock_guard<std::mutex> lock( g_mutex );
// code to lock
} // end scope destroy guard unlock mutex
// other class code
}
Foo::someFunc() {
// Code to lock
std::lock_guard<std::mutex> lock( g_mutex );
}
I had discovered why it wasn't working properly for me. In my class's constructor it was calling a function from its parent or base class. The parent or base class was then calling a static member of this class and the static member function of this class was also using lock_guard on the same mutex.
After I found the problem; I had two options. I could of used 2 independent mutexes, one for the constructor specifically and one for the static method specifically. After some thought I figured well if I use 2, and I'm blocking the full constructor the current lock and mutex won't go out of scope until the class instance is destroyed; however the life of the class will be nearly the full life of the application. Then if I used a second mutex and lock guard within the static method, it would be redundant to wrap another lock_guard around an existing one. So I came to the conclusion that I needed to create a scoped block { } for the code that needed to be blocked by the mutex so that it can be unlocked after this section goes out of scope, then the constructor is free to call the static method and it can reuse the same mutex as it is now free. The class is now working properly and it is not crashing nor throwing exceptions when it shouldn't be.

C++ - function end and local destruction order

I have following code:
class Class
{
public:
std::string Read()
{
std::lock_guard<std::mutex> lock(mutex_);
return data_;
}
private:
std::mutex mutex_;
std::string data_;
};
What will be executed first - will a local copy (temporary) be created of the data_ string on the stack as a result of the function and then the lock will release the mutex, or will it be other way?
If so, does following line resolve the problem?
return std::string(data_);
Mutex is supposed to protect concurrent read/write of the data_, so that those operations do not interfere.
The function returns the data_ as an rvalue, hence the result here will be calculated from the data_ member before the destructor of lock is executed (as the function exits) and the mutex_ released.
Is a temporary (the return value) calculated before the mutex is released? Yes.
Is return std::string(data_); required? No.