C++ 如何控制无锁环形缓冲区中的读/写指针?

C++ 如何控制无锁环形缓冲区中的读/写指针?,c++,c++11,atomic,C++,C++11,Atomic,我刚刚编写了一个无锁的环缓冲区dem,但在多读线程的情况下工作失败。在我的代码中,读和写指针是递增的。我不能保证读指针总是在写指针之后 这是我的put/get函数: template<class T> bool RingBuffer<T>::put( const T& node ) { // local the avaliable place while ( full() ) { if ( !waitForFull() ) retu

我刚刚编写了一个无锁的环缓冲区dem,但在多读线程的情况下工作失败。在我的代码中,读和写指针是递增的。我不能保证读指针总是在写指针之后

这是我的put/get函数:

template<class T>
bool RingBuffer<T>::put( const T& node )
{
    // local the avaliable place
    while ( full() ) {
        if ( !waitForFull() ) return false;
    }

    ::std::size_t pos = m_front.fetch_add(1);
    while( !__sync_bool_compare_and_swap( &m_statusBuffer[ locate(pos) ], NS_WRITEABLE, NS_WRITEPENDING ) ) {
        if ( m_statusBuffer[ locate(pos) ] == NS_READPENDING ) {
            // wait for read complete
            continue;
        }

        while ( full() ) {
            if ( !waitForFull() ) return false;
        }

        pos = m_front.fetch_add(1);
    }
    fprintf( stderr, "put pos: %ld, front: %ld, rear: %ld\n", pos, m_front.load(), m_rear.load() );

    // update data
    m_circularBuffer[ locate(pos) ]   = node;
    m_statusBuffer[ locate(pos) ]     = NS_READABLE;

    return true;
}

template<class T>
::std::tuple<T, bool> RingBuffer<T>::get()
{   
    while ( empty() ) {
        if ( !waitForEmpty() ) return ::std::make_tuple( T(), false );
    }

    // local the avaliable place
    ::std::size_t pos = m_rear.fetch_add(1);
    while( !__sync_bool_compare_and_swap( &m_statusBuffer[ locate(pos) ], NS_READABLE, NS_READPENDING ) ) {
        if ( m_statusBuffer[ locate(pos) ] == NS_WRITEPENDING ) {
            // wait for write complete
            continue;
        }

        while ( empty() ) {
            if ( !waitForEmpty() ) return ::std::make_tuple( T(), false );
        }

        pos = m_rear.fetch_add(1);
    }
    fprintf( stderr, "get pos: %zd, front: %ld, rear: %ld\n", pos, m_front.load(), m_rear.load() );

    // update value
    auto ret = m_circularBuffer[ locate(pos) ];
    m_statusBuffer[ locate(pos) ]   = NS_WRITEABLE;

    return ::std::make_tuple( ret, true );
}
模板
bool-RingBuffer::put(常量T和节点)
{
//可利用的地方
while(full()){
如果(!waitForFull())返回false;
}
:std::size\u t pos=m\u front.fetch\u add(1);
while(!\u同步\u bool\u比较\u和\u交换(&m\u statusBuffer[locate(pos)],NS\u可写,NS\u可写)){
如果(m_statusBuffer[locate(pos)]==NS_READPENDING){
//等待读取完成
继续;
}
while(full()){
如果(!waitForFull())返回false;
}
pos=m_front.fetch_add(1);
}
fprintf(标准,“放置位置:%ld,前部:%ld,后部:%ld\n”,位置,m_-front.load(),m_-rear.load());
//更新数据
m_circularBuffer[locate(pos)]=节点;
m_statusBuffer[locate(pos)]=NS_可读;
返回true;
}
模板
::std::tuple RingBuffer::get()
{   
while(empty()){
if(!waitForEmpty())返回::std::make_tuple(T(),false);
}
//可利用的地方
::std::size\u t pos=m\u-rear.fetch\u-add(1);
while(!\u同步\u bool\u比较\u和\u交换(&m\u statusBuffer[locate(pos)],NS\u可读,NS\u READPENDING)){
如果(m_statusBuffer[locate(pos)]==NS_WRITEPENDING){
//等待写入完成
继续;
}
while(empty()){
if(!waitForEmpty())返回::std::make_tuple(T(),false);
}
pos=m_后方。取_添加(1);
}
fprintf(stderr,“获取位置:%zd,前面:%ld,后面:%ld\n”,位置,m_front.load(),m_rear.load());
//更新值
自动返回=m_循环缓冲[定位(位置)];
m_statusBuffer[locate(pos)]=NS_可写;
return::std::make_tuple(ret,true);
}
空/满是:

template<class T>
bool RingBuffer<T>::empty()
{
    return ( m_rear.load() >= m_front.load() );
}

template<class T>
bool RingBuffer<T>::full()
{
    //return ( ( m_front.load() >= m_rear.load() && ( m_front.load() - m_rear.load() ) >= m_mask ) );
    return ( m_front.load() - m_rear.load() ) >= m_mask );
}
模板
bool-RingBuffer::empty()
{
返回(m_后.load()>=m_前.load());
}
模板
bool-RingBuffer::full()
{
//返回((m_front.load()>=m_rear.load()&&&(m_front.load()-m_rear.load())>=m_mask));
返回(m_front.load()-m_reast.load())>=m_mask);
}
当我使用多线程时,读指针将跨过写指针,然后阻塞或核心转储


如何修复此错误?

在无锁环形缓冲区中,可以在写入程序和读取程序之间进行同步。这通常是通过比较写指针和读指针(或索引)来实现的,而只有编写器可以更改写指针,而读取器只能更改读指针。您计划使用什么机制使多个读卡器与无锁访问同步?我会说这个概念很奇怪,或者至少不清楚。我为多个编写者同时编写添加了一个额外的状态buff,这也会影响读取操作。但是它带来了很多错误。谢谢你的回答。我会尝试完全分离读者和作者。将
std::atomic
与遗留
\u sync
内置软件混合使用应该是不必要的。我建议从最好的例子中学习。