退出时,多线程Qt应用程序不会停止

gro*_*190 5 c++ qt multithreading opencv qthread

我正在编写一个简单的Qt程序来捕获来自摄像头的视频(使用OpenCV).我正在使用一个QThread循环,捕获图像并将它们提供给MainWindow对象的对象.这是应该的.

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

QThread:线程仍在运行时被销毁.

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

main.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();
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

camerathread

#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
Run Code Online (Sandbox Code Playgroud)

该程序包含的代码多于此,但我只包含了我认为与该问题相关的代码.如有必要,我会发布其余的.

Nej*_*jat 3

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

while(!finishThread)
{
   cv::Mat img;
   vc >> img;
   matHandler->handleMat(img);
}
Run Code Online (Sandbox Code Playgroud)

您应该设置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!
}
Run Code Online (Sandbox Code Playgroud)

另外,您不应该直接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();
Run Code Online (Sandbox Code Playgroud)

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

另外,在类的析构函数中,Application以某种方式退出线程,如所述。