普通双锁队列, 当判断是不是首尾相同时(即队列是不是为空),还是会 既加头锁又加尾锁。好在有聪明人早在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 <mutex>
#include <memory>
#include <functional>
#include <condition_variable>
template <typename T>
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<T> try_pop()
{
std::unique_lock<std::mutex> 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<T> new_data(std::make_shared<T>(std::forward<T>(t)));
std::unique_ptr<node> new_tail(new node);
node *p = new_tail->get();
{
std::unique_lock<std::mutex> 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<T> data;
std::unique_ptr<node> next;
};
std::mutex head_mut;
std::mutex tail_mut;
std::unique_ptr<node> head;
node *tail;
std::condition_variable data_cond;
private:
node* get_tail()
{
std::unique_lock<std::mutex> ulkt(tail_mut);
return tail;
}
};
template <typename T>
class threadsafe_queue2<T*>
{
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<std::mutex> 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<std::mutex> 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<std::mutex> ulkt(tail_mut);
return tail;
}
};
#endif
因回家后,代码是凭借回忆改的, 可能会有错。大概意思 就是这么个意思。 性能我测试的,大概较之前普通的首尾锁能提高10%到20%。
对了,try_pop使用的时候需要用,
std::shared_ptr<T> data = xxx.try_pop();
版权声明:本文为sexiao0100原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。