在QObjects之间的不同线程上连接信号/槽

时间:2013-01-27 15:41:50

标签: qt signals-slots qthread qobject

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

MainWindow.cpp

Qt::Directconnection

ObjectA.h

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

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

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

ObjectA.cpp

#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;
}

ObjectB.h

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.cpp

#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;
}

2 个答案:

答案 0 :(得分:4)

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

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

如果您现在在一个线程中编写代码,但希望以后准备将其移动到其他线程,那么最好使连接排队。这样,单个线程的行为将基本相同,emit将立即返回,之后您不会感到意外。

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

答案 1 :(得分:1)

根据您的评论,您的主题正忙于QWaitCondition,因此它无法处理信号。如果您确实需要QWaitCondition,则可以使用QCoreApplication::processEvents和超时对插槽进行轮询,例如

while(true) {
    if(condition.wait(&mutex, 1000)) {
        // process condition
    } else {
        QCoreApplication::processEvents()
    }
}

但这涉及处理信号的延迟(在本例中为1秒)。除此之外,还有类似的question on SO 建议摆脱QWaitCondition并使用信号/插槽。