欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

单生产者单消费者的环形队列

程序员文章站 2024-03-18 11:38:34
...

环形队列设计如下:

template <class T>
class ring
{
puclic:
    explicit ring(int size): m_maxsize(size), m_rp(0), m_wp(0)
    {   
        if (size < 2)
        {
            throw std::runtime_error("too few elements, size must grater than 1");
        }
        m_array = new T[size+1];
    }
    
    ~ring
    {
        delete [] m_array;
    }
    bool full()const
    {
        return inc(wp) == rp;
    }


    bool empty()const
    {
        return rp == wp;
    }


    int inc(int n)const
    {
        return ++n % (maxsize+1);
    }


    int push_back(const T& v)
    {
       if (full()) 
        {
            return -1;
        }
        m_array[m_wp] = v;
        m_wp = inc(m_wp);
        return 0;
    }
    
    int pop_front(T& v)
    {
        if (empty())
        {
            return -1;
        }
        v = m_array[m_rp];
        m_rp = inc(m_rp);
        return 0;
    }
    
    size_t size()const
    {   
        size_t n = m_wp - m_rp;
        return n > 0 ? n : m_maxsize + n;
    }
    
private:
    T* m_array;
    int m_maxsize;
    int m_rp __attribute__((align(8)));
    int m_wp __attribute__((align(8)));
    
}




考虑如下情况,单生产者,单消费者
1.读线程追赶写线程,但empty()条件rp == wp一直为true,即使不加锁也线程安全
2.写线程追赶读线程,单full()条件wp++ == rp一直
3.极端情况下
rp=wp=m_maxsize
读写线程按如下指令执行:
写线程                      读线程
wp++
                            empty() rp == wp 为false
                            rp++
                            rp = 0   rp翻转
                            empty()为false 可读
wp = 0 wp翻转
                            rp++    rp=1,这个时候读索引已经在写索引前,数据读取异常
                            
4.所以rp,wp的操作必须是原子的,根据Intel手册8.1.1节的介绍:


从Intel486 processor开始,以下的基本内存操作是原子的:
• Reading or writing a byte(一个字节的读写)
• Reading or writing a word aligned on a 16-bit boundary(对齐到16位边界的字的读写)
• Reading or writing a doubleword aligned on a 32-bit boundary(对齐到32位边界的双字的读写)


从Pentium processor开始,除了之前支持的原子操作外又新增了以下原子操作:
• Reading or writing a quadword aligned on a 64-bit boundary(对齐到64位边界的四字的读写)
• 16-bit accesses to uncached memory locations that fit within a 32-bit data bus(未缓存且在32位数据总线范围之内的内存地址的访问)


所以__attribute__((align(8)))可保证索引读写的原子性


 

相关标签: 环形队列 c