• 线程安全的 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 ();
        }
    };
  • 相关阅读:
    Hibernate学习笔记
    Servlet:从入门到实战学习(3)---Servlet实例【图文】
    Servlet:从入门到实战学习(2)---Servlet生命周期
    Servlet:从入门到实战学习(1)---全·环境配置
    java复习(9)---数据库JDBC
    java复习(8)---I/O
    java复习(7)---集合类、泛型
    java复习(6)---异常处理
    C#尝试读取或写入受保护的内存。这通常指示其他内存已损坏
    C# TTS 文本转语音中断实现方式
  • 原文地址:https://www.cnblogs.com/wuOverflow/p/4296671.html
Copyright © 2020-2023  润新知