实现一个线程安全的双向链表(C++)

简介

最近实现了一个线程安全的双向链表,使用的是C++类的模式写的,和以前学习数据结构使用struct结构体实现的方式不同,对函数进行了封装,以及使用了C++中的类模板,还有unique_lock锁,对内存泄漏也进行了优化。
如果想继续学习各种锁的使用,请关注我,我后面会陆续更新各种锁的使用。如有错误的地方欢迎评论区指出。
以下是代码:(注意:请勿在业务代码中使用,代码未经过完全的测试)

内存泄漏的思考

请看如下代码的对比,上面的存在内存泄漏,下面的不存在内存泄漏。
原因是:上面的代码执行后,中间结点的内存是没有释放的(由于RAII,内存会在程序结束的时候进行释放),如果有指针指向了其中的结点,程序依然可以访问到结点的值,这显然是我们不想看到的。
在改进后,下面的代码对不要的结点都进行了显示的内存释放,这样就不存在内存泄漏了。

/*
// 这里存在内存泄漏
template<typename T>
void DoubleList<T>::Clear(){
    unique_lock<mutex> mtx (mtx_list);
    head->next = tail;
    tail->pre = head;
    length = 0;
}
*/
template<typename T>
void DoubleList<T>::Clear(){
    unique_lock<mutex> mtx (mtx_list);
    auto p = head->next;
    while(p != tail){
        head->next = p->next;
        delete p;
        p = head->next;
    }
    length = 0;
}

代码实现

#include <iostream>
#include <mutex>
#include <thread>
using namespace std;

template <typename T>
class ListNode{
    public:
        T val;
        ListNode* next;
        ListNode* pre;

};

template<typename T>
class DoubleList{
    public:
        DoubleList(){};
        ~DoubleList(){};
        void  InitList();
        bool Insert(int pos,T data);
        bool Erase(int pos);
        void Clear();
        ListNode<T>* Find(T target);
        void Print();
        int getlength();
    private:
        mutex mtx_list;
        ListNode<T>* head;
        ListNode<T>* tail;
        int length;
};

template<typename T>
int DoubleList<T>::getlength(){
    return length;
}

template<typename T>
void DoubleList<T>::InitList(){
    unique_lock<mutex> mtx (mtx_list);
    head = new ListNode<T>();
	tail = new ListNode<T>();
	head->next = tail;
	head->pre = nullptr;
	tail->next = nullptr;
	tail->pre = head;
	length = 0;
}

template<typename T>
bool DoubleList<T>::Insert(int pos,T data){
    unique_lock<mutex> mtx (mtx_list);
    if(pos > length || pos < 0){
        return false;
    }
    ListNode<T>* pre = head, *p = head->next;
    ListNode<T>* temp = new ListNode<T>();
    temp->val = data;
    while(pos){
        pre = p;
        p = p->next;
        --pos;
    }
    temp -> next = p;
    pre->next = temp;
    temp->pre = p->pre;
    p->pre = temp;
    temp = nullptr;
    ++length;
    return true;
}

template<typename T>
bool DoubleList<T>::Erase(int pos){
    if(pos < 0){
        return false;
    }
    unique_lock<mutex> mtx (mtx_list);
    if(pos > length || length == 0){
        return false;
    }else{
        ListNode<T>* pre = head, *p = head->next;
        while(pos > 0){
            pre = p;
            p = p->next;
            --pos;
        }
        pre->next = p->next;
        p->next->pre = p->pre;
        delete p;
        --length;
        return true;
    }
}
/*
// 这里存在内存泄漏
template<typename T>
void DoubleList<T>::Clear(){
    unique_lock<mutex> mtx (mtx_list);
    head->next = tail;
    tail->pre = head;
    length = 0;
}
*/

template<typename T>
void DoubleList<T>::Clear(){
    unique_lock<mutex> mtx (mtx_list);
    auto p = head->next;
    while(p != tail){
        head->next = p->next;
        delete p;
        p = head->next;
    }
    length = 0;
}


template<typename T>
ListNode<T>* DoubleList<T>::Find(T target){
    unique_lock<mutex> mtx (mtx_list);
    ListNode<T>* p = head->next;
    while(p != tail){
        if(p->val == target){
            return p;
        }
        p = p->next;
    }
    return nullptr; 
}

template<typename T>
void DoubleList<T>::Print(){
    unique_lock<mutex> mtx(mtx_list);
    ListNode<T>* p = head->next;
    if (length == 0)
	{
		std::cout << "List is empty" << std::endl;
		return;
	}
    while(p != tail){
        std::cout << p->val << " ";
        p = p->next;
    }
    cout << endl;
}


int main(){
    DoubleList<int> L;
    L.InitList();
    // 写
    thread t1 ([&L](){
        for(int i=0; i < 5000;++i){
            L.Insert(0,1);
        }
    });
    thread t2 ([&L](){
        for(int i=0; i < 5000;++i){
            L.Insert(0,2);
        }
    });

    t1.join();
    t2.join();

    L.Print();
    if(L.getlength() == 10000){
        cout << "success" <<endl;
    }else{
        cout << "fail" << endl;
    }
    cout << L.getlength()<<endl;


    // 查找
    thread t3 ([&L](){
        for(int i=4000; i < 6000; ++i){
            auto p = L.Find(i);
        }
    });
    thread t4 ([&L](){
        for(int i=2000; i < 3000; ++i){
            auto p = L.Find(i);
        }
    });
    t3.join();
    t4.join();


    //删除
    thread t5 ([&L](){
        for(int i=4000; i < 6000; ++i){
            auto p = L.Erase(i);
        }
    });
    thread t6 ([&L](){
        for(int i=2000; i < 3000; ++i){
            auto p = L.Erase(i);
        }
    });
    t5.join();
    t6.join();
    
    cout << L.getlength() <<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

强大的RGG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值