2017-08-31 71 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; 
} 

您可能需要有一個隊列,或某種機制來存儲一個固定的緩衝區數量。