[英]Is std::mutex as a member variable thread-safe for multiple threads?
[英]Is it thread-safe to access a Mat with multiple threads in OpenCV?
我想加速一個算法(完整的本地二進制模式與圓形鄰居),我遍歷所有像素並用它的鄰居計算一些東西(所以我需要鄰居像素訪問)。
目前我通過用一個線程/進程迭代所有像素來做到這一點。 我想通過將輸入圖像分成多個 ROI 並單獨計算每個 ROI(使用多個線程)來並行化此任務。
這里的問題是,ROI 是重疊的(因為要計算一個像素,有時我需要看遠處的鄰居),並且多個線程可能同時訪問像素數據( READING )。 如果兩個或多個線程同時在相同的索引上讀取相同的 Mat,這是一個問題嗎?
如果我寫入相同的 Mat 並行但使用不同的索引,這也是一個問題嗎?
通常,並行讀取不是問題,因為cv::Mat
只是一個很好的數組包裝器,就像std::vector
(是的,存在差異,但我看不出它們會如何影響此處的主題所以我將忽略它們)。 然而,並行化不會自動為您帶來性能提升。 這里有很多事情需要考慮:
創建線程需要大量資源,如果任務相對較短(就計算時間而言)可能會產生很大的負面影響,因此必須考慮線程池。
如果您編寫高性能代碼(無論是多線程還是單線程),您應該了解您的硬件是如何工作的。 在這種情況下:內存和 CPU。 Timur Doumler 在 CppCon 2016 上有一個關於這個話題的非常好的演講。 這應該可以幫助您避免緩存未命中。
另外值得一提的是編譯器優化。 打開它。 我知道這聽起來非常明顯,但是 SO 上有很多人詢問有關性能的問題,但他們不知道編譯器優化是什么。
最后,還有 OpenCV Transparent API (TAPI),它基本上使用 GPU 而不是 CPU。 幾乎所有 OpenCV 的內置算法都支持 TAPI,你只需要傳遞一個cv::UMat
而不是cv::Mat
。 這兩種類型可以相互轉換。 但是,轉換很耗時,因為UMat
基本上是 GPU 內存 (VRAM) 上的一個數組,這意味着每次轉換時都必須復制它。 訪問 VRAM 也比訪問 RAM 花費的時間更長(對於 CPU 而言)。 但是,您必須記住,如果不將 VRAM 數據復制到 RAM,就無法使用 CPU 訪問 VRAM 數據。 這意味着如果您使用cv::UMat
則無法迭代像素。 只有編寫自己的 OpenCL 或 Cuda 代碼才能在 GPU 上運行算法。
在大多數消費級 PC 中,對於滑動窗口算法(基本上是迭代像素並圍繞每個像素執行計算的任何算法),使用 GPU 通常是迄今為止最快的方法(但也需要最大的努力來實現)。 當然,這只適用於數據緩沖區(您的圖像)足夠大以使其值得復制到 VRAM 或從 VRAM 復制的情況下。
對於並行寫入:只要您沒有重疊區域,它通常是安全的。 然而,緩存未命中和錯誤共享(如 NathanOliver 所指出的)是需要考慮的問題。
只要讀操作沒有同時發生寫操作,多個並發讀操作是安全的。
這適用於任何健全的系統。
考慮替代方案:
如果存在競爭條件,則意味着存儲對象的內存在讀取操作期間被修改。 如果在讀取期間沒有寫入內存(存儲對象),則線程之間不可能進行交互。
最后,如果您查看文檔,
https://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html
你會看到兩次提到線程安全:
因此,在不同線程中異步操作相同的矩陣是安全的。
他們提到在矩陣分配期間執行的引用計數。 因此,至少可以在多個線程中安全地從同一個矩陣分配給另外兩個矩陣。 這幾乎保證了簡單的讀取訪問也是線程安全的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.