Как управлять указателем чтения / записи в безблокировочном кольцевом буфере? - PullRequest
0 голосов
/ 15 октября 2019

Я просто пишу безблокировочный демон ringbuffer, но работа не удалась с многопоточными потоками. В моем коде указатели чтения и записи увеличиваются. Я не могу гарантировать, что указатель чтения всегда будет после указателя записи.

Это моя функция 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 );
}

и пустое / полное значение:

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 );
}

Когда я использую многопоточность, указатель чтения перешагнет указатель записи, а затем заблокирует или сбросит память.

Как я могу исправить эту ошибку?

...