如何保护缓冲区不使用多个线程?

时间:2017-08-31 18:40:42

标签: c++ algorithm locking mutex semaphore

我的实施存在缺陷,我无法弄清楚。我有一个工作线程,不一致地调用回调写入名为" m_bufferLatest"的缓冲区。需要复制缓冲区,并且在主线程中完成复制需要一些时间。所以我需要保护" m_bufferLatest"。所以在我调用ContinuousCapture()的主线程中,我设置了一个名为" m_skipFrame"的标志。这样回调生病不会写入m_bufferLatest。

但是当我运行我的程序时,m_bufferLatest为null,具体取决于工作线程的运行速度。

有人可以帮我解决一下我的程序有什么问题吗?

bool HandleEofCallbackCont() 
{
    std::lock_guard<std::mutex> lock(m_EofMutex);

    if (!m_skipFrame) {
        //here update m_bufferCont
        if (!m_camera->SaveLatestFrameToQueue())
        {
            printf("get latest frame failed.. \n");
        }

    }

        m_EofFlag = true;
    }
    m_EofCond.notify_one();

    return true;
}

bool ContinuousCapture(Settings settings)
{
    //wait for the condition variable otherwise timeout
    std::unique_lock<std::mutex> lock(m_EofMutex);
    {
        if (!m_EofFlag)
        {
            m_EofCond.wait_for(lock, std::chrono::seconds(10), [&]() {
                return (m_EofFlag);
            });
        }

        m_skipFrame = true;

        int size = m_camera->m_bufferBytes / sizeof(uns16);

        //transfer from data
        if (!TransferData(settings, (uns16*)m_camera->m_bufferLatest, size, m_Frame))
        {
            printf("transfer data failed");
            return false;
        }

        m_skipFrame = false;
        m_EofFlag = false;
    }

    return true;
}

这就是我想要做的。 enter image description here

1 个答案:

答案 0 :(得分:0)

为了在两个线程之间进行同步,使用同步原语非常重要。还可以减少系统被互斥锁锁定的时间。虽然互斥锁允许在不同线程之间保证状态,但它们倾向于表现出单线程性能。

m_SkipFrame = true;

在一个线程上可见,但需要发生某种形式的interthread-happens-before以确保其他线程不起作用。

std::atomic<> is a good mechanism, for testing state between the threads.

假设你只有一个读者和一个作家。以下方案最简单。

  1. 创建一个类来封装缓冲区。该类将用于将信息从作者传递给读者。
  2. 在交互类中使用指向此的指针,但将其存储在std :: atomic
  3. 将完成的指针放在阅读器或编写器中。
  4. 假设一个类持有缓冲区。

    class BufferHolder {
    };
    

    然后在Interthread类中

    class Interthread {
        std::atomic<BufferHolder*> m_Exchange;
    }
    

    那么作家就是......

    void Interthread::Writer( BufferHolder * pNewBuffer ) {
       BufferHolder * oldBuffer = m_Exchange.exchange( pNewBuffer );
       delete oldBuffer; // may be nullptr, but that is ok.
       // if the oldBuffer wasn't used, it was sort of wasted.
    }
    
    BufferHolder * Interthread::Reader() {
       BufferHolder * pNewBuffer = m_Exchange.exchange( nullptr );
       return pNewBuffer;
    }
    

    您可能需要一个队列或某种机制来存储固定数量的缓冲区。