线程安全堆栈实现

Thread safe stack implementation

本文关键字:实现 堆栈 安全 线程      更新时间:2023-10-16

阅读

Anthony Williams的"C++ Concurrency in Action"(第1版)

您可以找到线程安全堆栈的以下实现:

struct empty_stack: std::exception
{
const char* what() const throw()
{
return "empty stack";
}
};  
template<typename T>  
class threadsafe_stack  
{  
private:
std::stack<T> data;
mutable std::mutex m;  
public:
threadsafe_stack(){}
threadsafe_stack(const threadsafe_stack& other)
{
std::lock_guard<std::mutex> lock(other.m);
data=other.data;
}
threadsafe_stack& operator=(const threadsafe_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(std::make_shared<T>(data.top()));
data.pop();
return res;
}
void pop(T& value)
{
std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw empty_stack();
value=data.top();
data.pop();
}
bool empty() const
{
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
};  

因此,在讨论可能的实现时,作者提出了 pop() 的下一个版本:

void pop(T& value)  
{  
std::lock_guard<std::mutex> lock(m);  
if(data.empty()) throw empty_stack();  
value=data.top();  
data.pop();  
}  

并突出显示了一些注意事项,其中一个警告是,此解决方案要求存储在堆栈中的类型必须是可分配的。

同时,他展示了下一个用法示例:

std::vector<int> result;
some_stack.pop(result);

现在我的反对意见:在我看来,需要另一个警告:存储在线程安全堆栈中的类型的赋值运算符不得像 std::

vector 的赋值运算符那样抛出异常。

我的反对是基于吗?

我反对的理由:它源于对作者提出的下一个解决方案(未实现)的分析:

"如果 return by value 不能抛出异常,你可以编写一个值返回 pop(),所以存储在线程安全堆栈中的类型需要一个不抛出的复制构造函数或移动构造函数"。

谢谢你的时间。

为什么你觉得抛出empty_stack是可以的,但抛出向量赋值可能抛出的任何内容就不行了?

T pop()的问题在于它需要首先从堆栈中删除值,然后复制它 - 这可能会抛出,此时您将丢失值; 它既不会返回也不会留在容器中。换句话说,这样的设计不能提供强有力的例外保证。

这就是为什么std::stack提供了两个单独的调用 -T top()读取顶部而不修改堆栈(如果抛出,堆栈保持不变),以及修改堆栈并保证不抛出的void pop()