线程安全的 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 ();

    }

};

 

你可能感兴趣的:(stack)