【发布时间】:2014-08-10 15:15:37
【问题描述】:
这是书中的示例代码:
#include <exception>
struct empty_stack: std::exception
{
const char* what() const throw();
};
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(std::move(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>(std::move(data.top())));
data.pop();
return res;
}
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();
}
};
上面写着:
empty() 和其中一个之间可能存在竞争条件 pop() 函数,但是因为代码显式检查 包含堆栈为空,同时在 pop() 中持有锁,这场比赛 条件没有问题
如果它们都在“全局”互斥锁被锁定时完成,这怎么可能是竞争条件?
【问题讨论】:
-
可能只是一本写得不好的书?
-
想一想如果使用该类的人写了例如会发生什么
while (!stack.empty()) stack.pop();在多个线程中。 -
@JoachimPileborg 所以你是说这两个操作需要在同一个锁中完成? API 看起来不太好——暴露的太多了。
-
完全正确,除了公开不太理想的互斥体之外,没有其他好的方法。但是,您可以添加一个新函数
pop_all,将谓词作为参数,然后pop_all函数对每个弹出项目调用谓词进行循环和弹出。
标签: c++ multithreading locking