在 QObjects 之间跨不同线程连接信号/插槽 [英] connecting signal/slot across different threads between QObjects

查看:82
本文介绍了在 QObjects 之间跨不同线程连接信号/插槽的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道在 MainWindow 的构造函数中创建的两个 QObjects 之间连接信号/插槽的最佳实践是什么,但稍后移动到不同的线程......当我使用选项 连接时,默认连接似乎不起作用Qt::Directconnection 事情开始工作...但有时信号/插槽失败...以下是我的代码模式...请告诉我是否需要更改我的类设计...

I wanted to know what is the best practice to connect signal/slots between two QObjects created in the contructor of MainWindow but moved to different threads later...default connections seems not working then when I connect with the option Qt::Directconnection things start working...but sometimes the signal/slot fails...following is my code pattern..please let me know if I need to change my class design...

MainWindow.cpp

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
{
   myObjectA = new ObjectA;
   myObjectB = new ObjectB;

   connect( myObjectA,SIGNAL(signalA()),myObjectB,SLOT(slotB()) );

   myObjectA.initiateProcess();
   myObjectB.initiateProcess();
}

ObjectA.h

#include <QThread>
#include <QObject>

class ObjectA : public QObject
{
    Q_OBJECT
public:
    explicit ObbjectA(QObject *parent = 0);
    void inititateProcess();
public slots:
    void do_job();

signals:
    void signalA();
private:
    QThread *worker;
}

ObjectA.cpp

ObjectA::ObjectA(QObject* parent)
{
  ....
}

void ObjectA::do_jobA()
{
  //do something;
}

void ObjectA::initiateProcess()
{
  worker = new QThread;
  connect(worker,SIGNAL(started()),this,SLOT(do_jobA()));
  this->moveTo(worker);
  worker->start()
}

ObjectB.h

#include <QThread>
#include <QObject>

class ObjectB : public QObject
{
    Q_OBJECT
public:
    explicit ObjectB(QObject *parent = 0);
    void initiateProcess();
public slots:
    void do_job();
    void slotB();

signals:
    void signalB();//for some other slot
private:
    QThread *worker;
}

ObjectB.cpp

ObjectB::ObjectB(QObject* parent)
{
  ....
}

void ObjectB::do_jobB()
{
  //do something;
}

void ObjectB::initiateProcess()
{
  worker = new QThread;
  connect(worker,SIGNAL(started()),this,SLOT(do_jobB()));
  this->moveTo(worker);
  worker->start()
}

推荐答案

总的来说,作为个人意见,即使在线程中,我也不会将阻塞代码(例如 QWaitCondition)与事件循环混合使用,除非你知道它不会阻塞很长时间.对于 GUI 线程,我会说长"超过 100 毫秒(比这更长,即使在传统的桌面应用程序中,用户体验也开始受到影响),但对于其他线程,它可能会更长,这取决于可以阻止所有的时间线程需要处理的事件和信号.

In general, as a personal opinion, I would not mix blocking code (like that QWaitCondition) with event loop even in a thread, unless you know it will not block for long. For GUI thread, I'd say "long" is more than 100ms (longer than that and user experience starts to suffer even in traditional desktop apps), but for other threads it may be much longer, depending on how long it's ok block all events and signals that thread needs to handle.

对于多线程,通常最好对信号使用自动或显式排队连接.直接连接将在发出信号的线程中执行,如果接收对象存在于另一个线程中,则需要使插槽(以及类中相关的所有内容)成为线程安全的.不这样做要简单得多,也更安全,要跟踪的事情就少了.

With multiple threads, it's generally better to use automatic or explicitly queued connections for signals. Direct connection will execute in the thread where signal is emitted, and if receiving object lives in another thread, then the slot (and as a consequence, everything releated in the class) needs to be made thread safe. Much simpler and safer to not do it that way, one less thing to keep track of.

如果你现在在一个线程中编写代码,但想准备稍后将其移动到另一个线程,那么最好使连接排队.这样一来,单线程的行为就基本相同了,emit 将立即返回,以后您不会有任何意外.

If you write code now in one thread, but want to prepare to move it to other thread later, then better make the connection queued. That way the behaviour will be largely same already with single thread, emit will return immediately, and you get no surprises later.

如果您想编写在任何线程中阻塞不确定或过长时间的代码,最好将 QThread 子类化,覆盖 QThread::run() 和永远不要在其中调用 exec() .然后你可以在你自己的循环中使用 QMutex 和 QWaitCondition ,或者使用其他一些传统"的线程间通信方法.您仍然可以从线程发出信号,但连接应该排队以避免线程问题.还要记住,您添加到 QThread 的任何插槽都应该在 QThread 对象所在的线程中执行,而不是在 run() 方法正在执行的线程中执行.这实际上是一种非常方便的模式,您可以在 QThread 子类的插槽中隐藏"所有实际的线程交互代码(请记住,它们不会在运行 run() 的线程中执行),只要请注意不要长时间锁定其中使用的任何 QMutex.

If you want to write code that blocks for undetermined or otherwise too long time in any thread, it's better to subclass QThread, override QThread::run() and never call exec() in it. Then you can use QMutex and QWaitCondition in your own loop, or use some other "traditional" inter-thread communication method. You can still emit signals from the thread, but connections should be queued to avoid threading problems. Also remember that any slots you add to the QThread should execute in the thread where QThread object lives, not the thread where run() method is executing. This is actually quite convenient pattern, you can "hide" all actual thread interaction code in the slots of your QThread subclass (remember, they do not execute in the thread where run() runs), as long as you take care not lock any QMutex used in these for too long time.

这篇关于在 QObjects 之间跨不同线程连接信号/插槽的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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