简单的C++高并发安全队列

普通双锁队列, 当判断是不是首尾相同时(即队列是不是为空),还是会 既加头锁又加尾锁。好在有聪明人早在96年就想到了一个更妙的算法。这个算法也是用了head和tail两个锁,但是它有一个关键的地方是它在队列初始化的时候head和tail指针不为空,而是指向一个空节点。在enqueue的时候只要向队列尾部添加新节点就好了。而dequeue的情况稍微复杂点,它要返回的不是头节点,而是head->next,即头节点的下一个节点。

此方法参考http://www.parallellabs.com/2010/10/25/practical-concurrent-queue-algorithm/

下面是我参考https://blog.csdn.net/mymodian9612/article/details/53608084?utm_source=blogxgwz1

修改的简单C++(Linux也可用)高并发安全队列

 

#ifndef __THREADSAFE_QUEUE2_H_
#define __THREADSAFE_QUEUE2_H_
 
#include 
#include 
#include 
#include 
 
template 
class threadsafe_queue2
{
 
public:
 
    threadsafe_queue2()
    {
        node *nd = new node();
        nd->next = nullptr;
        head = node;
        tail = node;
    }
    threadsafe_queue2(const threadsafe_queue2&) = delete;
    threadsafe_queue2 operator=(const threadsafe_queue2&) = delete;
    ~threadsafe_queue2() = default;
    
    std::shared_ptr try_pop()
    {
        std::unique_lock ulkh(head_mut);
        if(head.get()->next == nullptr)
            return nullptr;
        auto old_head = std::move(head);
        head = std::move(old_head->next);
        return head->data;
    }
    
    
    void push(T &&t)
    {
        std::shared_ptr new_data(std::make_shared(std::forward(t)));
        std::unique_ptr new_tail(new node);
        node *p = new_tail->get();
        {
            std::unique_lock ulkt(tail_mut);
            p->data = new_data;
            p->next = nullptr;
            tail->next = std::move(new_tail);
            tail = p;
        }
        data_cond.notify_one();
    }
    
private:
 
    struct node
    {
        std::shared_ptr data;
        std::unique_ptr next;
    };
    
    std::mutex head_mut;
    std::mutex tail_mut;
    std::unique_ptr head;
    node *tail;
    std::condition_variable data_cond;
    
private:
 
    node* get_tail()
    {
        std::unique_lock ulkt(tail_mut);
        return tail;
    }
 
};
 
template 
class threadsafe_queue2
{
 
public:
 
    threadsafe_queue2()
    {
        node *nd = new node();
        nd->next = nullptr;
        head = node;
        tail = node;
    }
    threadsafe_queue2(const threadsafe_queue2&) = delete;
    threadsafe_queue2 operator=(const threadsafe_queue2&) = delete;
    
    ~threadsafe_queue2()
    {
        node *pre;
        for (; head->next != nullptr;)
        {
            pre = head;
            head = head->next;
            delete pre;
        }
        delete head;
    }
    
    T* try_pop()
    {
        node *old_head = nullptr;
        {
            std::unique_lock ulkh(head_mut);
            if (head->next == nullptr)
                return nullptr;
            old_head = head;
            head = head->next;
        }
        T *data = head->data;
        delete old_head;
        return data;
    }
    
    void push(T *t)
    {
        node *new_tail = new node;
        {
            std::unique_lock ulkt(tail_mut);
            tail->data = t;
            tail->next = new_tail;
            tail = new_tail;
        }
        data_cond.notify_one();
    }

private:

    struct node
    {
        T *data;
        node *next;
    };
    
    std::mutex head_mut;
    std::mutex tail_mut;
    node *head;
    node *tail;
    std::condition_variable data_cond;

private:

    node* get_tail()
    {
        std::unique_lock ulkt(tail_mut);
        return tail;
    }

};

#endif

因回家后,代码是凭借回忆改的, 可能会有错。大概意思 就是这么个意思。 性能我测试的,大概较之前普通的首尾锁能提高10%到20%。

对了,try_pop使用的时候需要用,

  std::shared_ptr data = xxx.try_pop();

 

你可能感兴趣的:(C++)