《C++ Concurrency in Action》笔记7 mutex(2)pop和top问题

来源:互联网 发布:国密算法介绍.pdf 编辑:程序博客网 时间:2024/06/06 08:49

虽然在类中封装mutex可以对数据进行并发保护,但是有些时候光对每个操作进行保护是不够的。看下面的代码:

template<typename T,typename Container=std::deque<T> >class stack{public:explicit stack(const Container&);explicit stack(Container&& = Container());template <class Alloc> explicit stack(const Alloc&);template <class Alloc> stack(const Container&, const Alloc&);template <class Alloc> stack(Container&&, const Alloc&);template <class Alloc> stack(stack&&, const Alloc&);bool empty() const;size_t size() const;T& top();T const& top() const;void push(T const&);void push(T&&);void pop();void swap(stack&&);};

这是一个stack类的接口,他的问题是empty()和size()不可信。看下面的代码:

stack<int> s;if(!s.empty()){int const value=s.top();s.pop();do_something(value);}

如果两个线程同时执行上诉操作,就会出问题。比如s恰好剩下一个元素时,一个线程刚刚检查完empty()函数,认为不为空,同时另一个线程已经将最后一个元素pop出去了,那么接着执行top操作会引发异常。最简单的解决方法是加try/catch语句,但会使得代码繁琐,而且emoty函数也成了鸡肋,没必要判断了。另外就是top和pop分离带来的不同步问题。即使stack内部做了mutex保护,仍然无法解决这类问题。

一种解决方案是将top和pop两种操作组合在一起,虽然这其中因拷贝构造引发的异常已经有人提供有效的解决方案,但同时也引来潜在的问题。

考虑一个stack<vector<int>>,如果copy一个这样的对象,必然需要申请堆内存,如果此时系统内存负荷沉重,或者有严格的资源约束,则有可能分配失败。此时会抛出std::bad_alloc异常。如果pop()函数定义成从stack中删除并返回这个值,这个值返回给调用者是发生在stack被修改后,但是copy操作可能引发异常。结果就是,stack被修改了,但是返回的值在拷贝给调用者时却失败了。所以,stack接口的设计者友好的将其分开为两个操作:top()和pop(),即使top()引发的copy失败,stack仍然完好如初。

那么,如何解决我们关注的问题呢?

请看下篇笔记


阅读全文
0 0
原创粉丝点击