C++ 评论我的并发队列
这是我编写的并发队列,我计划在正在编写的线程池中使用它。我想知道是否有任何性能改进,我可以做<代码>原子计数器粘贴在下面,如果您好奇的话C++ 评论我的并发队列,c++,concurrency,queue,C++,Concurrency,Queue,这是我编写的并发队列,我计划在正在编写的线程池中使用它。我想知道是否有任何性能改进,我可以做原子计数器粘贴在下面,如果您好奇的话 #ifndef NS_CONCURRENT_QUEUE_HPP_INCLUDED #define NS_CONCURRENT_QUEUE_HPP_INCLUDED #include <ns/atomic_counter.hpp> #include <boost/noncopyable.hpp> #include <boost/smart
#ifndef NS_CONCURRENT_QUEUE_HPP_INCLUDED
#define NS_CONCURRENT_QUEUE_HPP_INCLUDED
#include <ns/atomic_counter.hpp>
#include <boost/noncopyable.hpp>
#include <boost/smart_ptr/detail/spinlock.hpp>
#include <cassert>
#include <cstddef>
namespace ns {
template<typename T,
typename mutex_type = boost::detail::spinlock,
typename scoped_lock_type = typename mutex_type::scoped_lock>
class concurrent_queue : boost::noncopyable {
struct node {
node * link;
T const value;
explicit node(T const & source) : link(0), value(source) { }
};
node * m_front;
node * m_back;
atomic_counter m_counter;
mutex_type m_mutex;
public:
// types
typedef T value_type;
// construction
concurrent_queue() : m_front(0), m_mutex() { }
~concurrent_queue() { clear(); }
// capacity
std::size_t size() const { return m_counter; }
bool empty() const { return (m_counter == 0); }
// modifiers
void push(T const & source);
bool try_pop(T & destination);
void clear();
};
template<typename T, typename mutex_type, typename scoped_lock_type>
void concurrent_queue<T, mutex_type, scoped_lock_type>::push(T const & source) {
node * hold = new node(source);
scoped_lock_type lock(m_mutex);
if (empty())
m_front = hold;
else
m_back->link = hold;
m_back = hold;
++m_counter;
}
template<typename T, typename mutex_type, typename scoped_lock_type>
bool concurrent_queue<T, mutex_type, scoped_lock_type>::try_pop(T & destination) {
node const * hold;
{
scoped_lock_type lock(m_mutex);
if (empty())
return false;
hold = m_front;
if (m_front == m_back)
m_front = m_back = 0;
else
m_front = m_front->link;
--m_counter;
}
destination = hold->value;
delete hold;
return true;
}
template<typename T, typename mutex_type, typename scoped_lock_type>
void concurrent_queue<T, mutex_type, scoped_lock_type>::clear() {
node * hold;
{
scoped_lock_type lock(m_mutex);
hold = m_front;
m_front = 0;
m_back = 0;
m_counter = 0;
}
if (hold == 0)
return;
node * it;
while (hold != 0) {
it = hold;
hold = hold->link;
delete it;
}
}
}
#endif
\ifndef NS\u并发队列\u水电站\u包括在内
#定义NS_并发_队列_水电站_包括在内
#包括
#包括
#包括
#包括
#包括
名称空间ns{
模板
类并发队列:boost::noncopyable{
结构节点{
节点*链接;
T常数值;
显式节点(T常量和源):链接(0),值(源){}
};
节点*m_前;
node*m_back;
原子计数器;
互斥类型m_互斥;
公众:
//类型
类型定义T值_类型;
//建筑
并发队列():m_前端(0),m_互斥体(){}
~concurrent_queue(){clear();}
//容量
std::size\u t size()常量{return m\u counter;}
bool empty()常量{return(m_counter==0);}
//修饰语
无效推送(T常数和源);
旅行社(旅游目的地和目的地);
无效清除();
};
模板
void并发队列::push(T const和source){
节点*保持=新节点(源);
作用域锁定类型锁定(m_互斥);
if(空())
m_front=保持;
其他的
m_back->link=保持;
m_back=保持;
++m_计数器;
}
模板
bool并发队列::try\u pop(T和destination){
节点常数*保持;
{
作用域锁定类型锁定(m_互斥);
if(空())
返回false;
保持=m_前;
如果(m_前==m_后)
m_前=m_后=0;
其他的
m_front=m_front->link;
--m_计数器;
}
目的地=持有->价值;
删除保留;
返回true;
}
模板
无效并发队列::清除(){
节点*保持;
{
作用域锁定类型锁定(m_互斥);
保持=m_前;
m_front=0;
m_back=0;
m_计数器=0;
}
如果(保持==0)
返回;
节点*it;
while(保持!=0){
它=保持;
保持=保持->链接;
删除它;
}
}
}
#恩迪夫
原子计数器
#ifndef NS_ATOMIC_COUNTER_HPP_INCLUDED
#define NS_ATOMIC_COUNTER_HPP_INCLUDED
#include <boost/interprocess/detail/atomic.hpp>
#include <boost/noncopyable.hpp>
namespace ns {
class atomic_counter : boost::noncopyable {
volatile boost::uint32_t m_count;
public:
explicit atomic_counter(boost::uint32_t value = 0) : m_count(value) { }
operator boost::uint32_t() const {
return boost::interprocess::detail::atomic_read32(const_cast<volatile boost::uint32_t *>(&m_count));
}
void operator=(boost::uint32_t value) {
boost::interprocess::detail::atomic_write32(&m_count, value);
}
void operator++() {
boost::interprocess::detail::atomic_inc32(&m_count);
}
void operator--() {
boost::interprocess::detail::atomic_dec32(&m_count);
}
};
}
#endif
#如果包含NDEF NS(原子)计数器(HPP)
#定义包含的NS_原子_计数器_HPP_
#包括
#包括
名称空间ns{
类原子计数器:boost::noncopyable{
易失性增强::uint32μt mμu计数;
公众:
显式原子计数器(boost::uint32_t value=0):m_计数(value){}
运算符boost::uint32\u t()常量{
返回boost::进程间::详细信息::原子读取32(常量转换(&m)计数);
}
void运算符=(boost::uint32\u t值){
boost::进程间::细节::原子写入32(&m\U计数,值);
}
void运算符++(){
boost::进程间::细节::原子计数(&m计数);
}
无效运算符--(){
boost::进程间::细节::原子计数(&m计数);
}
};
}
#恩迪夫
我认为在这种情况下,由于为每个新节点调用new
,链接列表会遇到性能问题。这不仅仅是因为调用动态内存分配器速度慢。这是因为调用它经常会引入大量并发开销,因为在多线程环境中,免费存储必须保持一致
我会使用一个向量,当它太小而无法容纳队列时,可以将其调整为更大。我永远不会把它调整得更小
我会安排前面和后面的值,这样向量就是一个环形缓冲区。但这需要在调整大小时移动图元。但这应该是一个相当罕见的事件,可以通过在施工时给出建议的向量大小在一定程度上缓解
或者,您可以保留链表结构,但决不销毁节点。只需继续将其添加到空闲节点队列中。不幸的是,空闲节点的队列将需要锁定才能正确管理,我不确定您是否真的处于比一直调用delete和new更好的位置
您还可以使用向量获得更好的参考位置。但我不确定这将如何与CPU之间来回穿梭的缓存线交互
有些人建议使用
::std::deque
,我认为这不是一个坏主意,但我怀疑环形缓冲区向量是一个更好的主意。Herb Sutter提出了一种无锁队列的实现,它肯定会比您的更好:)
其主要思想是使用缓冲环,在队列运行期间完全放弃内存的动态分配。这意味着队列可能已满(因此您可能必须等待将元素放入),这在您的情况下可能是不可接受的
正如Omnifarious所指出的,最好不要使用链表(用于缓存位置),除非您分配了一个池。我会尝试使用
std::deque
作为后端,它对内存友好得多,并且保证只要您只弹出并推送(在前面和后面),就不会有任何重新分配,这是队列通常的情况。您有具体的问题要问,还是要解决的区域?所以这不是一个代码审查网站。我做了一个编辑,表示我对性能改进的建议感兴趣。你看过Herb Sutter的DDJ文章()吗?他讨论了一些性能改进(对push和pop使用不同的锁,对缓存线大小填充成员变量)。更一般地说,您为什么要实现自己的而不是使用,例如TBB的并发队列
?在try\u pop
中可能存在内存泄漏。如果复制构造函数抛出destination=hold->value
,那么hold
将永远不会被调用