1

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

主窗口.cpp

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

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

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

对象A.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;
}

对象A.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()
}

对象B.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;
}

对象B.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()
}
4

2 回答 2

4

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

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

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

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

于 2013-01-27T17:43:53.653 回答
1

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

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

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

于 2013-01-27T17:20:31.553 回答