2017-08-31 69 views
0

我的实现存在缺陷,我无法弄清楚。我有一个工作线程不一致地调用回调函数来写入名为“m_bufferLatest”的缓冲区。缓冲区需要被复制过来,并且需要一些时间才能在主线程中完成复制。所以我需要保护“m_bufferLatest”。因此,在我调用ContinuousCapture()的主线程中,我设置了一个名为“m_skipFrame”的标志,以便回调函数不会写入m_bufferLatest。如何保护使用多线程的缓冲区?

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

有人可以帮助我什么是我的程序错了吗?

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

立即突出显示的一件事情是,m_skipframe在互斥锁被锁定时设置,但在互斥体外进行检查。 – SergeyA

+0

另一件事 - 如果传输失败 - 标志仍然是真实的,所以不会再写入。你也在等待互斥锁下的EofCond。在这种情况下,你期望其他线程会做什么?我只会使用互斥锁来保护缓冲区并使标志原子化... –

+0

@SergeyA我将m_skipFrame移到互斥量中,但它仍然无效。我得到无效的访问内存。我已经更新了代码。 – user1296153

回答

0

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

m_SkipFrame = true; 

是可见的一个线程,而是某种形式的interthread-happens-before需要发生,以确保其他线程不工作。

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

假设你只有一个阅读器和一个作者。下面的方案将工作最简单。

  1. 创建一个类来封装缓冲区。这个类将用于将信息从作者传递给读者。
  2. 在您的交互类中使用指针,但将其存储在std :: atomic中
  3. 在读取器或写入器中处理完成的指针。

假设一个类包含缓冲区。

class BufferHolder { 
}; 

然后,一个线程间类

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

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