我的目标:将子线程生成的对象传递给主程序线程,在主线程中读取它,并尽可能少地复制它。
什么有效
子线程拥有的对象,以这个字段作为中间存储:
private:
cv::Mat rgb;
该字段的简单 getter 方法:
cv::Mat freenect2_pipe::take_rgb(){
return this->rgb;
}
在将对象发射到主线程时使用以上两种方式:
std::vector<cv::Mat> images;
while (!stop_requested && !pause_requested
&& rgbd_camera.Capture(images)
) {
rgb = images[0];
emit rgb_frame(take_rgb());
}
信号定义:
void rgb_frame(const cv::Mat& image);
什么不起作用
-发射 (a) rgb_frame(images[0])
,(b) rgb_frame(rgb)
,或 (c) rgb_frame(locally_created_copy_of_frame)。
它在哪里/如何失败?
尝试从生成的对象(在本例中为 OpenCV 矩阵)中读取时出现段错误。
*我如何实现目标?*s
附加信息
1) 上面的 images
数组是在第三个非 qt 线程中生成的,该线程由子线程启动。这发生在我无法修改的第三方代码中。
2) 无论我使用 QThreads 还是 C++11 线程(可能在我的平台上都在后台使用 pthread),段错误行为都是一致的。当直接使用 C++11 线程时,我创建了自己的中间共享缓冲区。因此 (void) 被发出,但主线程从队列上的共享缓冲区中弹出对象。然而,读取完全在同一个地方失败。
[编辑]
插槽定义:void tmp_display_rgb2(const cv::Mat& rgb);
最佳答案
有两种通用的解决方案。
#1 和#2 最小化复制,但只有#2 最小化内存分配。
解决方案 1:重新创建一个新的 shared_ptr 并在每次循环运行时在其中重新分配所需的数据项。使用线程之间共享的缓冲区来存储中间结果。
while (playback_allowed
&& rgbd_camera.Capture(*images)) {
this->buffer->push_back(images); //push onto the buffer
emit frame();
images = hal::ImageArray::Create(); //re-initialize the shared pointer
}
解决方案 2(理论):在数据采集源处,创建一个交换缓冲区,在两个内存位置之间进行交换。在与上面的 Capture
方法等效的过程中,源一次应该只写入其中一个,返回指向该位置的指针,并在下一次迭代时交换位置。如果一切设置正确,生产者线程将在 Capture 敢于覆盖正在使用/处理的位置之前阻塞。
我能做的最好的就是使用解决方案 #1,因为我没有修改/覆盖/替换 Capture
方法的自由,该方法总是重新分配 的内容>图像
。我采用了纯 C++11 线程解决方案,使用信号/插槽作为握手,并测试了两种缓冲区实现:一种使用锁,一种使用乐观重试。
理论上,也可以使用QThreads,缓冲区可能被Qt信号/槽机制提供的隐式队列所取代,这将需要发射整个shared_ptr。
关于c++ - 使用 Qt/C++ 从单独的线程发出对象时如何避免复制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31258946/