在 OpenCV 中访问具有多个线程的 Mat 是否线程安全?
Is it thread-safe to access a Mat with multiple threads in OpenCV?
我想加速一种算法(带有圆邻居的完整局部二进制模式(,为此我遍历所有像素并用它计算一些东西邻居(所以我需要邻居像素访问(。
目前,我通过使用一个线程/进程遍历所有像素来做到这一点。我想通过将输入图像划分为多个ROI并分别计算每个ROI(使用多个线程(来并行执行此任务。
这里的问题是,ROI是重叠的(因为要计算一个像素,有时我需要查看远处的邻居(,并且多个线程可能同时访问像素数据(READING(。如果两个或多个线程同时在同一索引上读取相同的垫子,这是一个问题吗?
如果我写入相同的 Mat 并行但在不同的索引上,这也是一个问题吗?
只要没有同时对读取进行写入,就可以安全地进行多个并发读取。
这适用于任何理智的系统。
考虑替代方案:
如果存在争用条件,则意味着存储对象的内存在读取操作期间被修改。如果在读取过程中没有写入内存(存储对象(,则线程之间不可能进行交互。
最后,如果你看一下文档,
https://docs.opencv.org/3.1.0/d3/d63/classcv_1_1Mat.html
您将看到两次提及线程安全:
因此,在 不同的线程。
他们提到它在矩阵分配期间执行的引用计数中。因此,至少,从同一矩阵分配给另外两个矩阵可以在多个线程中安全地完成。这几乎保证了简单的读取访问也是线程安全的。
一般来说,并行读取不是问题,因为cv::Mat
只是数组的一个很好的包装器,就像std::vector
一样(是的,有差异,但我看不出它们如何影响这里的主题问题,所以我将忽略它们(。但是,并行化不会自动提升性能。这里有很多事情需要考虑:
创建线程的资源量很大,如果任务相对较短(就计算时间而言(,则可能会产生很大的负面影响,因此必须考虑线程池。
如果您编写高性能代码(无论是多线程还是单线程(,您应该掌握硬件的工作原理。在这种情况下:内存和CPU。Timur Doumler在CppCon 2016上就这个话题做了很好的演讲。这应该可以帮助您避免缓存未命中。
值得一提的是编译器优化。打开它。我知道这听起来非常明显,但是SO上有很多人问有关性能的问题,但他们不知道编译器优化是什么。
最后,还有OpenCV透明API(TAPI(,它基本上利用GPU而不是CPU。OpenCV的几乎所有内置算法都支持TAPI,您只需传递cv::UMat
而不是cv::Mat
即可。这两种类型可以相互转换。但是,转换是耗时的,因为UMat
基本上是 GPU 内存 (VRAM( 上的数组,这意味着每次转换时都必须复制它。此外,访问 VRAM 比访问 RAM(对于 CPU(花费的时间更长。 但是,您必须记住,如果不将其复制到RAM,则无法使用CPU访问VRAM数据。这意味着如果您使用cv::UMat
,则无法迭代像素。只有当您编写自己的 OpenCL 或 Cuda 代码以便您的算法可以在 GPU 上运行时,才有可能。
在大多数消费级PC中,对于滑动窗口算法(基本上是迭代像素并围绕每个像素执行计算的任何内容(,使用GPU通常是迄今为止最快的方法(但也需要最多的努力来实现(。当然,这仅在数据缓冲区(您的图像(足够大以使其值得复制到 VRAM 和从 VRAM 复制时才成立。
对于并行写作:只要您没有重叠区域,它通常是安全的。但是,缓存未命中和错误共享(如NathanOliver指出的那样(是需要考虑的问题。
- 从不同线程使用int64的不同字节安全吗
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 在C++中使用cURL和多线程
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在cuda线程之间共享大量常量数据
- 如何将元素添加到数组的线程安全函数?
- 线程,如果else语句,都是错误的上下文切换后,会发生什么
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 异常属于C++中的线程还是进程
- C++中的线程安全删除
- C++使用params创建线程函数会导致转换错误
- 类与私有变量的其他类之间的线程安全性
- CoInitialize()在单独的线程上崩溃而不返回
- c++中的线程池
- Qt-工作线程崩溃时将cv::Mat转换为QImage
- 在 OpenCV 中访问具有多个线程的 Mat 是否线程安全?
- C++ cv::Mat 返回向量的<rectangle>线程异步
- cv::imshow 在不同的线程上不显示 cv::mat 颜色
- 如何在不同的线程中将图像数据从BitmapSource(WPF)复制到C++/CLI中的cv::Mat(OpenCV)