#include <exception>
struct empty_stack: std::exception
{
const char* what() const throw();
};
template<typename T>
class thread_safe_stack
{
private:
std::stack<T> data;
mutable std::mutex m;
public:
stack(){}
stack(const stack& other)
{
std::lock_guard<std::mutex> lock(other.m);
data=other.data;
}
stack& operator=(const stack&) = delete;
void push(T new_value)
{
std::lock_guard<std::mutex> lock(m);
data.push(new_value);
}
std::shared_ptr<T> pop()
{
std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw empty_stack();
std::shared_ptr<T> const res(new T(data.top());
data.pop();
return res;
}
void pop(T& value)
{
std::lock_guard<std::mutex> lock(m); // #1
if(data.empty()) throw empty_stack();
value=data.top();
data.pop();
}
bool empty() const
{
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
};
Question How can the data.empty() return in the following statement,
if(data.empty()) throw empty_stack();
given the void pop(T& value) has locked the mutex already #1.
/// Updated ///
Here is my understanding,
#1 already lock the mutex and will release when the pop(T&value) returns. Now in the middle of this function, the code calls data.empty() which in turn locks the mutex again. Since the mutex has been locked, so the function empty cannot get it.
That’s a call to
std::stack::empty, notthread_safe_stack::empty. So it isn’t trying to acquire the mutex a second time.