基于锁的线程安全栈

学习并发数据结构的笔记,看这篇博客主要可以看代码,代码有注释


需要注意的点:

1、保证线程持有锁的时间最短;(最小保护区域原则

2、操作需要获取多个锁时,可能会产生死锁(死锁:不同的线程相互等待锁,各自得不到需要的锁);

3、在保证线程安全的前提下,提高并发访问的概率对数据结构;

4、调用不完全构造对象或是已经销毁对象的成员函数不可取;


存在的问题:

1、死锁问题:当持有一个锁的用户调用时,1、2、3处的拷贝构造和移动构造、拷贝赋值或者移动赋值,有造成死锁的风险;相当于说data本身的构造也是存在锁的。可如果控制不好,则能会造成死锁问题;如果data本身的构造不存在锁,则不会造成死锁问题;(注:需要考虑用户的data的构造里面有没有锁,会不会造成死锁

2、性能问题:在等待push的过程中、在等待empty时,会造成资源浪费;


#include <exception>
#include <stack>
#include <mutex>
#include <memory>


//定义异常,可以抛出异常,但是stack数据没有改变,则是安全;
struct empty_stack: std::exception
{
    
    
    const char* what() const throw()
    {
    
    
        return "empty stack";
    }
};

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));//1
    }
    std::shared_ptr<T> pop()
    {
    
    
        std::lock_guard<std::mutex> lock(m);
        if(data.empty()) throw empty_stack();
        //1、make_shared共享指针,线程安全;
        //2、make_shared的异常不会导致内存泄漏和修改statck数据,所以是安全的;
        //3、拷贝构造或者移动时可能有异常,但是不会内存泄漏,新创建的对象也会销毁,是安全的;
        std::shared_ptr<T> const res(
            std::make_shared<T>(std::move(data.top())));//2
        data.pop();
        return res;
    }
    void pop(T& value)//引用返回,也是安全的
    {
    
    
        std::lock_guard<std::mutex> lock(m);//加锁
        if(data.empty()) throw empty_stack();//在empty处重复加锁,属于良性竞争锁
        //1、拷贝和移动时会可能异常,但是不会修改statck数据,是安全的;
        value=std::move(data.top());//3
        data.pop();
    }
    bool empty() const
    {
    
    
        std::lock_guard<std::mutex> lock(m);//加锁
        return data.empty();
    }
};


参考:

1、《C+±Concurrency-In-Action-2ed》

猜你喜欢

转载自blog.csdn.net/KPer_Yang/article/details/130173709