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
将永远不会被调用