opencv 将QScopedPointer移动到线程

ubof19bj  于 2023-10-24  发布在  其他
关注(0)|答案(3)|浏览(142)

最近几周,我读了很多关于RAII的文章,并认为我应该开始在我的应用程序中使用智能指针。作为一个例子,我试图修改我的一个应用程序。它在线程中捕获来自网络摄像头的帧,在另一个线程中执行图像处理,并在QT小部件中显示处理后和未处理的图像。一个中心对象是CCameraObject,它控制捕获线程和图像处理线程。最多在这一点上,我在这个类中使用了4个普通指针作为成员:

CCameraCapture* m_CameraCapture;
CImageProcessor* m_ImageProcessor;
QThread* m_CameraCaptureThread;
QThread* m_ProcessingThread;

在CCameraScript的构造函数中,我使用new创建了Script,并将捕获对象移动到线程中:

m_CameraCaptureThread= new QThread();
m_CameraCapture= new CCameraCapture();
//Move camera capture object to thread
m_CameraCapture->moveToThread(m_CameraCaptureThread);

现在我想用QScopedPointer进行第一次测试,并尝试将m_CameraCapture更改为QScopedPointer,

QScopedPointer<CCameraCapture> m_CameraCapture;

并使用CameraCapture进行初始化(new CCameraCapture())在初始化列表中。它编译得很好,工作正常,但当我关闭应用程序时,析构函数被调用,我从Qt得到一个错误:“无法将事件发送到不同线程拥有的对象。当前线程5 ff 590. Receiver "(类型为'CCameraCapture')是在线程4 b7780中创建的”我猜它与m_CameraCapture->moveToThread有关(m_CameraCaptureThread);我现在移动一个作用域指针。QScopedPointer是否自动以CCameraCapture为父对象?

//This connections guarantees that the m_CCameraCapture and m_CameraCapture are deleted after calling QThread::exit()
QObject::connect(m_CameraCaptureThread, SIGNAL(finished()), m_CameraCaptureThread, SLOT(deleteLater()));
QObject::connect(m_CameraCaptureThread, SIGNAL(finished()), m_CameraCapture, SLOT(deleteLater()));

当摄像头捕获停止时,删除线程工作程序。如果m_CameraCapture现在是CCameraCapture的父级,可能会导致问题。目前我不确定在这种情况下使用SmartPointer是否是一个好主意。任何想法可能会导致这个错误的破坏?
编辑:CCameraExceptor看起来像这样(线程应该在worker之前删除):

CCameraHandler::~CCameraHandler(void)
{
//Stop grabbing and processing
emit stopGrabbing();
emit stopProcessing();
/*Wait for the capture thread to terminate. The destructor of CCamera Handler might be called on application close. Therefore it is important to wait for QThreads to terminate. Else the application might close before threads get deleted*/
m_CameraCaptureThread->exit();
m_CameraCaptureThread->wait();
//Wait for the processing thread to terminate
m_ProcessingThread->exit();
m_CameraCaptureThread->wait();
qDebug() << "CCameraHandler deleted";
}
dzjeubhm

dzjeubhm1#

已移动到另一个线程的对象必须被析构:
1.从线程本身,或
1.从任何线程 * 后 * 线程本身已被析构。
注意事项:QThread在你停止它之前被析构是不安全的。为了安全地对一个只运行事件循环的线程进行析构,你应该使用下面的子类:

class Thread : public QThread {
  using QThread::run; // final
public:
  Thread(QObject * parent = 0) : QThread(parent) {}
  ~Thread() { quit(); wait(); }
};

给定这样一个类,从GUI线程析构,你只需要在析构任何移动到线程的对象之前析构它。当然,根本没有必要将这些对象作为指针保存,但是下面的代码无论你直接保存它们还是作为指针保存它们都可以工作。

class Foo : public Bar {
  CCameraCapture m_CameraCapture;
  CImageProcessor m_ImageProcessor;
  Thread m_CameraCaptureThread;
  Thread m_ProcessingThread;
  ...
}

当类被析构时,将按顺序发生以下情况:

  1. ~Foo()主体运行(可能为空)。
  2. ...节中的成员(如果有的话)将按声明的相反顺序析构。
  3. m_ProcessingThread.~Thread运行,然后是超类析构函数(~QThread,最后是~QObject)。任何移动到该线程的对象现在都是无线程的。
  4. m_CameraCaptureThread.~Thread运行,然后是超类析构函数。任何移动到该线程的对象现在都是无线程的。
  5. m_ImageProcessor析构函数运行。作为一个无线程对象,析构对于任何线程都是安全的。
  6. m_CameraCapture析构函数运行。作为一个无线程对象,析构对于任何线程都是安全的。
    如果你使用QScopedPointer<...>来保存这些示例,事情会完全相同,只是每个对象的析构都将被 Package 在~QScopedPointer<...>的主体中。
    请注意,即使使用原始指针来保存这些示例也是过早的pessimization:您浪费了一点堆,并且由于额外的间接层,访问示例的速度有点慢。这些事情在孤立的情况下可能不会发挥很大作用,但是如果有成千上万的对象都以这种方式编码,事情就会增加。
    除非绝对必要,否则不要在单独的堆块中分配类成员。
cnwbcb6i

cnwbcb6i2#

如果你需要使用QScopedPointer的moveToThread示例,请查看here

h79rfbju

h79rfbju3#

问题是,你正在做一些UI的东西,从没有UI线程。这是很难告诉到底是哪里的问题,因为你没有给予信息,究竟是什么CCameraCapture做。
我怀疑在捕获一个帧后,你在标签上设置了一个pixmap(显示帧),而不是发出一个带有新帧的信号,并将这个信号与UI元素的相应插槽连接。所以我认为作用域指针和信号和插槽与你的问题无关,问题是你没有在需要的地方使用信号插槽机制。

相关问题