【问题标题】:Multithreaded Qt Application does not stop when quit多线程 Qt 应用程序在退出时不会停止
【发布时间】:2015-03-31 17:14:13
【问题描述】:

我正在编写一个简单的 Qt 程序来从摄像头捕获视频源(使用 OpenCV)。我正在使用一个循环的QThread 对象,捕获图像并将它们提供给MainWindow 对象。这正在正常工作。

问题是当我关闭时,应用程序(即按下“X”)相机捕获线程停止并且gui消失。但程序仍在后台运行。我还在应用程序输出中收到警告:

QThread:在线程仍在运行时销毁。

如何在退出时完全停止应用程序?

ma​​in.cpp

#include <QApplication>
#include "application.h"

using namespace cv;

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    Application app;
    app.init();

    return a.exec();
}

application.h

#include "mainwindow.h"
#include "camerathread.h"
#include "mathandler.h"
#include "tools.h"
#include "opencv2/core/core.hpp"

#ifndef APPLICATION
#define APPLICATION

class Application : public MatHandler{
    MainWindow w;
    CameraThread ct;
public:
    Application() {
        w.setFixedSize(800,600);
    }

    void init() {
        ct.setMatHandler(this);
        ct.start();
        w.show();
    }

    void handleMat(cv::Mat mat) {
        QImage qImage = toQImage(mat);
        w.setImage(qImage);
    }
};

#endif // APPLICATION

相机线程

#include <QThread>
#include "mathandler.h"
#include "opencv2/highgui/highgui.hpp"

#ifndef CAMERATHREAD
#define CAMERATHREAD

class CameraThread : public QThread {
    MatHandler *matHandler;
public:
    ~CameraThread() {
    }

    void setMatHandler(MatHandler *h) {
        matHandler = h;
    }

private: void run() {
        cv::VideoCapture vc(0);

        if (vc.isOpened()) {
            for(;;) {
                cv::Mat img;
                vc >> img;
                matHandler->handleMat(img);
            }
        }
    }
};

#endif // CAMERATHREAD

该程序包含比这更多的代码,但我只包含了我认为与问题相关的代码。如有需要,我会发布其余的。

【问题讨论】:

  • 检查除了UI和相机线程之外是否还有其他线程在运行。您正在使用的 API 可能会产生其他线程。
  • 我不知道如何检查这个...你能解释一下吗?
  • 检查正在运行的线程取决于您使用的 IDE(如果值得一试)。例如,此搜索:google.com/… 产生了以下结果:help.eclipse.org/indigo/… 但同样,这取决于您的 IDE。我刚刚演示了一个示例视图 /w Eclipse。

标签: c++ multithreading qt opencv qthread


【解决方案1】:

您的代码存在一些重大问题。首先,在你的 run 函数中,无休止的 for 循环将导致你的线程永远不会停止,除非你自己管理线程终止,例如:

while(!finishThread)
{
   cv::Mat img;
   vc >> img;
   matHandler->handleMat(img);
}

当应用程序将要关闭时,您应该将finishThread 设置为true。只需提供一个槽,您可以在其中设置finishThread 的值。当您想终止线程时,会发出一个信号,该信号连接到具有true 值的该插槽。之后等待线程正确完成几秒钟,如果它没有完成则强制它终止:

emit setThreadFinished(true); //Tell the thread to finish
if(!ct->wait(3000)) //Wait until it actually has terminated (max. 3 sec)
{
    ct->terminate(); //Thread didn't exit in time, probably deadlocked, terminate it!
    ct->wait(); //We have to wait again here!
}

你也不应该直接从其他线程调用handleMat 函数。它可能会导致您的应用程序崩溃或导致未定义的行为。为此使用信号/槽机制。将信号从您的线程连接到该插槽,并在每次您想调用它时沿着参数发出信号。

另一点是你最好从QObject 派生你的类并使用moveToThread。您可以在类的构造函数中执行此操作:

th = new QThread();

this->setParent(0);
this->moveToThread(th);

QObject::connect(th,SIGNAL(started()),this,SLOT(OnStarted()));
QObject::connect(th,SIGNAL(finished()),this,SLOT(OnFinished()));

th->start();

您的初始化和终止任务应分别在OnStarted()OnFinished() 插槽中完成。你可以有一个工作函数来运行重复操作。

同样在 Application 类的析构函数中,以某种方式退出线程。

【讨论】:

  • 感谢您的反馈,因为我(您可能已经意识到)C++ 和 Qt 编程的新手非常需要它。但有一件事我还不清楚。当我可以使用公共 void 方法停止应用程序时,为什么要在 CameraThread 中使用公共插槽?有什么优点/缺点?
  • 如果你使用一种方法来停止应用程序,那么你必须直接从Application 调用它,比如ct-&gt;setFinished(true);,这真的很危险。那是因为它们位于两个不同的线程中,并且同时从两个线程访问变量会导致未定义的行为。当你使用信号/槽机制来停止线程时,你要确保变量只能从一个线程访问(这里是CameraThread)。永远不要直接调用另一个线程中的对象的函数。
  • 注意,谢谢。关于主要问题;我按照您的建议将 ct->stop 代码添加到 Application 解构器中。还在 Thread 的解构器中添加了 QThread::exit()。关闭主窗口后应用程序仍在运行...
  • 你检查运行函数中的终止条件吗?你是否在析构函数中将终止条件设置为 true 并等待完成?
  • 是的,run 函数在 while 循环中断时结束。但是应用程序线程无限等待相机线程完成...pastebin.com/P2SA7YDD
猜你喜欢
  • 2012-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-14
  • 2013-01-28
  • 1970-01-01
相关资源
最近更新 更多