我的目标:将子线程生成的对象传递给主程序线程,在那里读取它,尽可能少地复制它。
什么有用
子线程拥有的对象,该字段为中间存储:
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(local_created_copy_of_frame)。
哪里/如何失败?
尝试从生成的对象读取时的Segfaults(在本例中为OpenCV矩阵)。
*我如何实现目标?* s
其他信息
1)上面的images
数组是在子线程启动的第三个非qt线程中生成的。这种情况发生在我无法修改的第三方代码中。
2)无论我使用QThreads还是C ++ 11线程(可能都在我平台的后台使用pthread),段错误行为是一致的。直接使用C ++ 11线程时,我创建了自己的中间共享缓冲区。因此(void)被发出,但主线程从que上的共享缓冲区弹出对象。但是,读取在同一个地方完全失败。
[编辑]
广告位定义:void tmp_display_rgb2(const cv::Mat& rgb);
答案 0 :(得分:0)
有两种通用解决方案。
#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
方法,返回指向该位置的指针,并在下一次迭代时交换位置。如果all设置正确,则生产者线程将在Capture敢于覆盖正在使用/处理的位置之前阻塞。
我能做的最好是使用解决方案#1,因为我没有自由修改/覆盖/替换Capture
方法,该方法总是重新分配images
的内容。我使用纯C ++ 11线程解决方案,使用signal / slot作为握手,并使用两个缓冲区实现进行测试:一个使用锁,一个使用乐观重试。
理论上,也可以使用QThreads,并且可以用Qt信号/槽机制提供的隐式队列替换缓冲区,这需要发出整个shared_ptr。