Qt线程之间的连接类型:为什么这样工作? [英] Qt connection type between threads: why does this work?

查看:130
本文介绍了Qt线程之间的连接类型:为什么这样工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在尝试使多相机系统使用不同的线程处理不同的相机时,我无法获得信号和插槽在不同线程之间正常工作。我知道发送信号的对象和相关插槽的对象生活在不同的线程,因此我知道我可能只需要为连接找到一个合适的连接类型参数的事实是错误的。最终,我发现只有使用Qt :: DirectConnection才能使一切正常工作。

While trying to make a multi-camera system work with a different thread handling a different camera, I couldn't get signals and slots working correctly between different threads. I knew something was wrong with the fact that the object sending the signal and the related slot's object were living in different threads, and thus I knew that I probably only had to find an appropriate "connection type" parameter for the connection. Eventually, I ended up discovering that only using Qt::DirectConnection would make everything work as it should.

找到下面的简化代码。

Find the simplified code below. Here's a small description of how everything should work.


  • 应用程序是一个主程序,它应该创建所有线程并启动他们。在这个简化的版本中,它只是等待工人通过插槽quit完成其工作。

  • Application is the main program which is supposed to create all the threads and start them. In this simplified version, it then simply waits for the worker to finish its jobs through the slot "quit".

Worker是执行其中一个线程任务。在这个简化的例子中,我只是等待一段时间才完成计算。然后工作者发出一个信号给应用程序实例,然后允许等待所有的线程并退出QCoreApplication。

Worker is the object which performs one of the threaded tasks. In this simplified example, I just wait some time before finishing the computation. The worker then emits a signal which is directed to the application instance, which is then allowed to wait for all the threads and quit QCoreApplication.

我发现如果我不在第二个连接中使用Qt :: DirectConnection,那么工作者的finished()信号不会触发线程的quit()槽,这意味着应用程序然后保持挂起等待线程。

What I am finding is that if I don't use Qt::DirectConnection in the second connect, then the finished() signal of the worker does not trigger the quit() slot of the thread, which means that the application then remains hanging waiting for the thread.

我的问题是:为什么会这样?因为两个对象(工人和线程)属于不同的线程,应该不是使用QueuedConnection,还是别的?我认为DirectConnection只能用于属于同一个线程的对象。

My question is: why is that so? since the two objects (the worker and the thread) belong to different threads, shouldn't I be using QueuedConnection, or something else? I thought DirectConnection should only be used for objects belonging to the same thread.

main.cpp:

#include <iostream>
#include <QCoreApplication>
#include "program.h"

using namespace std;

int main(int argc, char **argv) {
  QCoreApplication app(argc, argv);

  Program *p = new Program;
  p->execute();

  app.exec();

  delete p;
}

program.h

program.h

#ifndef _PROGRAM_H_
#define _PROGRAM_H_

#include <QThread>
#include <QTimer>
#include "worker.h"

class Program: public QObject {
  Q_OBJECT

  private:
    Worker *worker;
    QThread *thread;

  public:
    void execute();

  public slots:
    void quit();
};

#endif // _PROGRAM_H_

program.cpp

program.cpp

#include "worker.h"

using namespace std;

void Program::execute() {
  worker = new Worker();
  thread = new QThread;
  worker->moveToThread(thread);

  cout << "Connection established: "
        << connect(thread, SIGNAL(started()), worker, SLOT(process()))
        << endl;

  // slot not called if I remove the fifth parameter
  // or if I put Qt::QueuedConnection
  cout << "Connection established: "
        << connect(worker, SIGNAL(finished()), thread, SLOT(quit()),
                    Qt::DirectConnection)
        << endl;

  cout << "Connection established: "
        << connect(worker, SIGNAL(finished()), this, SLOT(quit()))
        << endl;

  cout << "Connection established: "
        << connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()))
        << endl;

  cout << "Connection established: "
        << connect(worker, SIGNAL(finished()), thread, SLOT(deleteLater()))
        << endl;

  thread->start();
}

void Program::quit() {
  cout << "waiting.." << endl;
  thread->wait();
  cout << "           .. I'm done!" << endl;

  cout << "quitting from all.." << endl;
  QCoreApplication::quit();
  cout << "           .. I'm done!" << endl;
}

#include "program_moc.cpp"



.h

worker.h

#ifndef _WORKER_H_
#define _WORKER_H_

#include <QObject>

class Worker: public QObject {
  Q_OBJECT

  public slots:
    void process();

  signals:
    void finished();
};

#endif // _WORKER_H_

worker.cpp:

worker.cpp:

#include <iostream>
#include <unistd.h>
#include "worker.h"

using namespace std;

void Worker::process() {
  cout << "Worker::process() started" << endl;
  usleep(1000000);

  cout << "Worker::finished() being emitted" << endl;
  emit finished();

  cout << "Worker::process() finished" << endl;
}

#include "worker_moc.cpp"

strong> EDIT

EDIT

以下@ariwez的回答确实解决了这个特定简化示例中的问题,

Following @ariwez 's answer does solve the problem in this specific simplified example, but it doesn't in a slightly more complex one, which I am adding now.

在此示例中,


  • 程序有自己的工作通过使用QTimer定期执行。程序还有另一个QTimer,用于模拟用户退出程序,从而触发槽的执行Program :: quit()。

  • Program has its own job to execute periodically through the use of a QTimer. Program also has yet another QTimer which is used to simulate the user quitting the program, which triggers the execution of the slot Program::quit().

Worker执行自己的工作,直到他的退出标志设置为false。这是在Program :: quit()内部完成的。

Worker executes its own job until his quitting flag gets set to false. This is done inside Program::quit().

发出finished()信号,它也应该与线程的quit()槽连接。然而,不知何故槽不能被执行,因为程序挂起等待线程。与前面的例子不同,重定位moveToThread过程并不能解决问题:当且仅当我使用Qt :: DirectConnection类型连接Worker :: finished()和QThread :: quit()和IThread不能理解为什么。

As in the previous example, worker successfully finishes its procedure and emits the finished() signal, which is also supposed to be connected with the thread's quit() slot. However, somehow the slot must not be executed, because Program hangs waiting for the thread. Differently from the previous example, relocating the moveToThread procedure does not solve the issue: everything works if and only if I use the Qt::DirectConnection type for the connection between Worker::finished() and QThread::quit(), and I can't understand why.

main.cpp:与上述相同

main.cpp: same as above

program.h:

program.h:

#ifndef _PROGRAM_H_
#define _PROGRAM_H_

#include <QThread>
#include <QTimer>
#include "worker.h"

class Program: public QObject {
  Q_OBJECT

  private:
    QTimer *timer, *quittingTimer;
    Worker *worker;
    QThread *thread;

  public:
    ~Program();

    void execute();

  private slots:
    void quit();
    void update();
};

#endif // _PROGRAM_H_

program.cpp:

program.cpp:

#include <iostream>
#include <QCoreApplication>
#include "program.h"
#include "worker.h"

using namespace std;

Program::~Program() {
  delete timer;
  delete quittingTimer;
}

void Program::execute() {
  timer = new QTimer();
  timer->setInterval(500);
  connect(timer, SIGNAL(timeout()), this, SLOT(update()));

  worker = new Worker;
  thread = new QThread;

  cout << "Connection established: "
        << connect(thread, SIGNAL(started()), worker, SLOT(process()))
        << endl;

  // doesn't work if I remove Qt::DirectConnection
  cout << "Connection established: "
        << connect(worker, SIGNAL(finished()), thread, SLOT(quit()),
                    Qt::DirectConnection)
        << endl;

  cout << "Connection established: "
        << connect(worker, SIGNAL(finished()), this, SLOT(quit()))
        << endl;

  cout << "Connection established: "
        << connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()))
        << endl;

  cout << "Connection established: "
        << connect(worker, SIGNAL(finished()), thread, SLOT(deleteLater()))
        << endl;

  worker->moveToThread(thread);

  timer->start();
  thread->start();

  // simulates user pressing key to close program
  quittingTimer = new QTimer();
  quittingTimer->singleShot(4000, this, SLOT(quit()));
}

void Program::quit() {
  cout << "timer->stop()" << endl;
  timer->stop();

  cout << "worker->quit()" << endl;
  worker->quit();

  cout << "thread->wait()" << endl;
  thread->wait();

  cout << "qcore->quit()" << endl;
  QCoreApplication::quit();
}

void Program::update() {
  cout << "Program::update() called" << endl;
}

#include "program_moc.cpp"



.h:

worker.h:

#ifndef _WORKER_H_
#define _WORKER_H_

#include <QObject>

class Worker: public QObject {
  Q_OBJECT
  private:
    bool quit_flag;

  public:
    void quit();

  public slots:
    void process();

  signals:
    void finished();
};

#endif // _WORKER_H_

worker.cpp:

worker.cpp:

#include <iostream>
#include <unistd.h>
#include <QThread>
#include "worker.h"

using namespace std;

void Worker::quit() {
  quit_flag = true;
}

void Worker::process() {
  quit_flag = false;
  while(!quit_flag) {
    cout << "Worker::process() is processing" << endl;
    usleep(300000);
  }
  cout << "Worker::finished() is being sent" << endl;
  emit finished();
  cout << "Worker::finished() is sent" << endl;
}

#include "worker_moc.cpp"

strong> EDIT 2

EDIT 2

重新阅读@ariwez的链接中的文章我发现这是第二个例子中的问题。问题是主事件循环正在中断,而等待线程的QThread :: finished()信号,因此Worker :: finished()信号不能被分派到QThread :: quit()槽。

Re-reading the article in @ariwez 's link I found out which was the problem in this second example. The problem was that the main event loop was being interrupted, while waiting for the thread's QThread::finished() signal, and so the Worker::finished() signal could not be dispatched into the QThread::quit() slot. So yeah, basically I deadlocked myself.

推荐答案

在连接之前你moveToThread,这就是为什么一切都在一个线程。

You moveToThread before connects that's why everything is in one thread.

这篇关于Qt线程之间的连接类型:为什么这样工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆