引用计数无锁queue的实现

结合外部计数及内部计数,代码目前只能在VS平台跑,clion和vc报编译器错误,

#include<bits/stdc++.h>
#include<thread>
#include<mutex>
#include<atomic>
using namespace std;
template<typename T>
class lock_free_queue {
public:
    atomic<int> size_;
private:
    struct node;
    struct counted_node_ptr {//next结点
        int external_count = 0;
        node* ptr = nullptr;
    };
    atomic<counted_node_ptr> head;
    atomic<counted_node_ptr> tail;
    struct node_counter {//结点计数器信息
        int  internal_count;       // 内部引用计数器值
        int external_counters;
    };

    struct node {
    public:
        atomic<T*> data;
        atomic<node_counter> count;//结点计数器的信息
        atomic<counted_node_ptr> next;
        node() {
            //node_counter new_count {0, 2}; //被tail指针和上一个结点的next指针指涉 引用计数为2 每次的新节点都是尾部
            node_counter new_count;
            new_count.internal_count = 0;
            new_count.external_counters = 2;
            count.store(new_count);
            next = { 0 };
        }
        void release_ref() {
            node_counter old_counter = count.load(memory_order_relaxed);
            node_counter new_counter;
            do {
                new_counter = old_counter;
                --new_counter.internal_count;//internal自减
            } while (!count.compare_exchange_strong(old_counter, new_counter, memory_order_acquire, memory_order_relaxed));
            if (!new_counter.internal_count && !new_counter.external_counters)
                delete this;
        }
    };
    static void increase_external_count(atomic<counted_node_ptr>& counter,
        counted_node_ptr& old_counter) {
        counted_node_ptr new_counter;
        do {
            new_counter = old_counter;
            ++new_counter.external_count;
        } while (!counter.compare_exchange_strong(old_counter, new_counter, memory_order_acquire, memory_order_relaxed));
        old_counter.external_count = new_counter.external_count;
    }

    static void free_external_counter(counted_node_ptr& old_node_ptr) {
        node* const ptr = old_node_ptr.ptr;
        int const count_increase = old_node_ptr.external_count - 2;
        node_counter old_counter = ptr->count.load(memory_order_relaxed);
        node_counter new_counter;
        do {
            new_counter = old_counter;
            --new_counter.external_counters;
            new_counter.internal_count += count_increase;
        } while (!ptr->count.compare_exchange_strong(old_counter, new_counter, memory_order_acquire, memory_order_relaxed));

        if (!new_counter.external_counters && !new_counter.internal_count)
            delete ptr;
    }

    void set_new_tail(counted_node_ptr& old_tail,
        counted_node_ptr const& new_tail) {
        node* const current_tail_ptr = old_tail.ptr;
        while (!tail.compare_exchange_weak(old_tail, new_tail) && old_tail.ptr == current_tail_ptr)
            ;
        if (old_tail.ptr == current_tail_ptr)
            free_external_counter(old_tail);
        else
            current_tail_ptr->release_ref();
    }

public:
    lock_free_queue() {
        counted_node_ptr headl;
        headl.ptr = new node();
        headl.external_count = 1;
        head.store(headl);
        tail.store(headl);
        this->size_ = 0;
    }
    void push(T new_value) {
      
        unique_ptr<T> new_data(new T(new_value));
        counted_node_ptr new_next;
        new_next.ptr = new node;
        new_next.external_count = 1;//自身为tail  被tail指针指涉
        counted_node_ptr old_tail = tail.load();
        while (true) {
            increase_external_count(tail, old_tail);//当前节点外部引用计数增加
            /*若有其他线程同时压入数据,就会始终看不到nullptr,只会看到传入的新值,导致重新循环(忙等--实质的锁),被阻塞的
            线程一直消耗CPU周期,等到最初调用push的线程执行完毕才停止*/
            T* old_data = nullptr;
            /*上述问题推导出 让等待的线程协助正在push的线程,以实现无锁队列*/
            if (old_tail.ptr->data.compare_exchange_strong(old_data, new_data.get()))
            {
                counted_node_ptr old_next = { 0 };
                if (!old_tail.ptr->next.compare_exchange_strong(old_next, new_next)) {
                    delete new_next.ptr;
                    new_next = old_next;
                }
                set_new_tail(old_tail, new_next);
                new_data.release();
                break;
            }
            else {
                counted_node_ptr old_next = { 0 };
                if (old_tail.ptr->next.compare_exchange_strong(old_next, new_next)) {
                    old_next = new_next;
                    new_next.ptr = new node;
                }
                set_new_tail(old_tail, old_next);
            }
        }  size_++;
    }

    unique_ptr<T> pop() {
       
        counted_node_ptr old_head = head.load(memory_order_relaxed);
        for (;;) {
            increase_external_count(head, old_head);

            node* const ptr = old_head.ptr;
            if (ptr == tail.load().ptr) {
                return unique_ptr<T>();
            }
            counted_node_ptr next = ptr->next.load();
            //线程将数据收为己有
            if (head.compare_exchange_strong(old_head, next)) {
                T* const res = ptr->data.exchange(nullptr);
                free_external_counter(old_head);
                return unique_ptr<T>(res);
            }
            ptr->release_ref();
        }
        
    }

    ~lock_free_queue() {
    }

};

template<typename T>
void init(lock_free_queue<T>& q) {
    for (int i = 0; i < 1000; i++)
        q.push(i);
}
template<typename T>
void put(lock_free_queue<T>& q) {
    int h = 1000; unique_ptr<int> v;
    while (true) {
        v = q.pop();
        if (v)
            cout << "数值:" << *v << " " << endl;
        else
            return;
    }
}
int main() {
    cout << "程开始" << endl;
    lock_free_queue<int> q;
    cout << "   size:" << q.size_ << endl;
    this_thread::sleep_for(chrono::seconds(2));
    vector<thread> ts;
    for (int i = 0; i < 50; i++) {
        ts.push_back(thread(&init<int>, ref(q)));
    }
    for (auto& x : ts)
        x.join();
    vector<thread> ts2;
    for (int i = 0; i < 5; i++) {
        ts2.push_back(thread(&put<int>, ref(q)));
    }

    for (auto& x : ts2)
        x.join();
    cout << "程序结束" << endl;
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值