0

I want to run two threads concurrently. I successfully did the same when I ran a program as a QT console application. Here's the working code of QT console application for multi threading:-

myobject.h

#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <QObject>
#include <QDebug>
#include <QThread>

class MyObject : public QObject
{
    Q_OBJECT
public:
    explicit MyObject(QObject *parent = 0);
    void doSetup(QThread &cThread);
    void doSetup2(QThread &cThread2);
signals:

public slots:
    void doWork();
    void doWork2();
};

#endif // MYOBJECT_H

main.cpp:

#include <QtCore/QCoreApplication>
#include <QThread>
#include <myobject.h>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QThread cThread, cThread2;
    MyObject cObject, cObject2;

    cObject.doSetup(cThread);
    cObject.moveToThread(&cThread);
    cObject2.doSetup2(cThread2);
    cObject2.moveToThread(&cThread2);
    cThread.start();
    cThread2.start();
    qDebug()<<"hello there ";
    return a.exec();
}

my object.cpp

#include "myobject.h"
#include <QThread>
#include "tftpServer.h"

MyObject::MyObject(QObject *parent) :
    QObject(parent)
{
}

void MyObject::doSetup(QThread &cThread)
{
    connect(&cThread, SIGNAL(started()), this, SLOT(doWork()));
}

void MyObject::doSetup2(QThread &cThread2)
{
    connect(&cThread2, SIGNAL(started()), this, SLOT(doWork2()));
}
void MyObject::doWork()
{
    for(int i=0; i<1000; i++)
    {
        qDebug()<<"******************Thread 1";


    }

}
void MyObject::doWork2()
{
    for(int i=1000; i<2000; i++)
    {
        qDebug()<<"Thread 2************************";


    }

}

Here's the output:

******************Thread 1
Thread 2************************
******************Thread 1
Thread 2************************
******************Thread 1
Thread 2************************
******************Thread 1
Thread 2************************

..and so on

Now when I use this almost same code and run as a QT GUI application, the threads do not run concurrently, but run one after the other. Here's the code:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDebug>
#include <QThread>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void doSetup(QThread &cThread);
    void doSetup2(QThread &cThread2);
private:
    Ui::MainWindow *ui;

public slots:
    void doWork();
    void doWork2();
};

#endif // MAINWINDOW_H

main.cpp

#include <QtGui/QApplication>
#include "mainwindow.h"
#include <QThread>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QThread cThread, cThread2;
    MainWindow cObject, cObject2;

    cObject.doSetup(cThread);
    cObject.moveToThread(&cThread);
    cObject2.doSetup2(cThread2);
    cObject2.moveToThread(&cThread2);
    cThread.start();
    cThread2.start();

    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>
#include <qthread.h>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    qDebug()<<"gui running";
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::doSetup(QThread &cThread)
{
    connect(&cThread, SIGNAL(started()), this, SLOT(doWork()));
}

void MainWindow::doSetup2(QThread &cThread2)
{
    connect(&cThread2, SIGNAL(started()), this, SLOT(doWork2()));
}
void MainWindow::doWork()
{
    //QThread::sleep(100);
    for(int i=0; i<1000; i++)
    {
      qDebug()<<"******************Thread 1";
//      qDebug()<<i;

    }

}
void MainWindow::doWork2()
{
    for(int i=1000; i<2000; i++)
    {
      qDebug()<<"Thread 2************************";
//        qDebug()<<i;

    }

}

Here's the output:

gui running 
gui running 
QObject::moveToThread: Widgets cannot be moved to a new thread
QObject::moveToThread: Widgets cannot be moved to a new thread
gui running 
******************Thread 1 
******************Thread 1 
******************Thread 1 
******************Thread 1

(and so on...)

******************Thread 1
Thread 2************************ 
Thread 2************************ 
Thread 2************************ 
Thread 2************************ 
Thread 2************************ 
Thread 2************************ 

(and so on...) Note that the only difference b/w console and gui application I made is changed the base class QObject to QMainWindow, and hence the thread objects so created are objects of QObject & QMainWindow respectively, for console and GUI applications.

Hoping I am sufficiently clear, can you please tell me what mistake am I committing, which is making the threads run one after the other and not concurrently, as it does for the console application?

Thank you.

cappy0704
  • 557
  • 2
  • 9
  • 30
  • also, in the output: QObject::moveToThread: Widgets cannot be moved to a new thread, I am guessing this line is explaining the problem. – cappy0704 Dec 31 '13 at 10:07
  • What are you trying to achieve, doWork must only be run once ? Does it access to any private member variables ? – Kirell Dec 31 '13 at 10:09

1 Answers1

4

Any class inherited from QWidget cannot reside in thread other than the main GUI thread. Actually this is what the output said. Your solution is a bad design. Separate the work objects (inherited from QObject, residing in another thread) and the visual objects (inherited from QWidget, residing in the GUI thread), to follow the "one class one responsibility" principle.

Another catch in multithreading in Qt is the fact that any QObject cannot reside in different thread than its parent. This is natural because the parent is the owner of the child object, most importantly it takes care of its destruction. To enable this, the child cannot be in other thread. Otherwise the parent might destroy an executing child, for example.

There are yet more catches, for example QPixmap cannot be in other thread than the main GUI etc.

  • @Vladmir, let me know if my understanding is correct: 1. the object of QObject i.e. cThread (in console app) object of QWidget (in GUI app) should be separate. But in the GUI app, i am not using QObject at all, ryt? 2. object of QObject class must reside in the same thread as the parent. Which is the parent class here? – cappy0704 Dec 31 '13 at 12:04
  • Sai: You can use QObjects in GUI app the same way as in console. QWidgets are primarily for visual representation, they are by no means replacement for QObjects. QObject in your example should do some work in the non-GUI thread (e.g. print out qDebug...). So basically keep your structure similar to what you had for console application. Then you only need to think about what exactly you want to show in your QWidget (which is why you have QWidget, right?). – HiFile.app - best file manager Dec 31 '13 at 13:55
  • Sai: ... Suppose you want for example to display a string in QLabel (for example) rather than print it with qDebug... in that case doWork of your QObject creates the string and then you should use signal-slot to pass it to your QWidget or QLabel. In some cases you can achieve the same even without signal-slot mechanism, but it usually has thread safety holes in it. – HiFile.app - best file manager Dec 31 '13 at 13:56
  • Sai: ... By child-parent I did not mean the inheritance, so it does not make sense to talk about which class is the parent. Each QObject in Qt can (but does not need to) have a parent. Parent is the object that you pass usually when calling the constructor of any QObject. Sometimes it is handy to have a parent because the parent can take care of the destruction so you do get memory leaks. But then you need to keep in mind that child must be in the same thread as the parent. If the QObject has no parent, then you can move it to whatever thread you like. – HiFile.app - best file manager Dec 31 '13 at 14:00
  • of course I meant "...do NOT get memory leaks..." in my last comment. :) – HiFile.app - best file manager Dec 31 '13 at 14:13