1
votes

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()
}
2
Your code works for me. Random guess of what might be wrong: Is it possible do_jobA or do_jobB doesn't terminate so the thread doesn't get a chance of executing its slot?jkozera
ok...thats a good guess coz in one of the do_job i have a while loop waiting on a QWaitcondition...but I need that while loop to make the object in one thread wait for some data coming from a different thread...rotating_image

2 Answers

4
votes

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.

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.

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.

1
votes

As per your comment, your thread is busy with QWaitCondition, so it can't process the signal. If you really need the QWaitCondition, you could do kind of polling for slots using QCoreApplication::processEvents and timeout, like

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

But this involves a delay in processing signals (1 second in this example). Other than this, there's a similar question on SO where it's recommended to get rid of QWaitCondition and use signals/slots instead.