线程安全的 stack

stack 不是一种容器, 而是一种适配器, 它的实现大概是这样的:

template<typename T, typename Container = 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&&);
};

可是这个版本并不是线程安全的, 比如:

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

假设这么一种情况, 对于只有一个元素的 s,线程 A 和线程 B 当前都已执行了 if 中的判断, 此时线程 A 得到了 value 的值, 然后执行 pop()。 但是, 在这之后,执行了线程的切换, 此时线程 B 开始师徒试图给 value 赋值, 可早已人去楼空。

那么, 怎样才能在线程安全的前提下得到栈顶的值并在复制之后 pop 它呢? 答案是这样:

template<typename Stack>
void empty_stack_check (const Stack& s)
{
    if (s.empty ()) {
        throw empty_stack ();
    }
}

struct empty_stack : std::exception
{
    const char* what () const throw();
};

template<typename T>
class thread_safe_stack
{
private:
    stack<T>      data;
    mutable mutex m;
public:
    using lockGuard = lock_guard<mutex>;
    thread_safe_stack () {}
    thread_safe_stack (const thread_safe_stack& other)
    {
        lockGuard lock (other.m);
        data = other.data;
    }

    stack& operator=(const thread_safe_stack&) = delete;

    void push (T new_value)
    {
        lockGuard lock (m);
        data.push (new_value);
    }

    shared_ptr<T> pop ()
    {
        lockGuard lock (m);
        empty_stack_check (data);

        shared_ptr<T> const res = 
            make_shared<T> (data.top());
        data.pop ();
        return res;
    }

    void pop (T& value)
    {
        lockGuard lock (m);
        empty_stack_check (data);
        value = data.top ();
        data.pop ();
    }

    bool empty () const
    {
        lockGuard lock (m);
        return data.empty ();
    }
};
原文地址:https://www.cnblogs.com/wuOverflow/p/4296671.html