使用Qt / C ++从单独的线程发出对象时如何避免复制?

时间:2015-07-07 02:51:16

标签: c++ multithreading qt c++11 memory

我的目标:将子线程生成的对象传递给主程序线程,在那里读取它,尽可能少地复制它。

什么有用

子线程拥有的对象,该字段为中间存储:

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);

1 个答案:

答案 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。