Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QThread with Android



  • Hi Guys
    I have written a code to demonstrate QThread on Android mobile.

    header:
    #ifndef FUNCTIONCLASS_H
    #define FUNCTIONCLASS_H
    #include <QObject>
    #include<QThread>
    #include<QDebug>
    class FunctionClass : public QObject
    {
         Q_OBJECT
    public:
        FunctionClass();
    signals: void signalofmainclass();
    public slots:
       void workdone();
    };
    #endif // FUNCTIONCLASS_H
    

    .CPP:

    #include "functionclass.h"
    
    FunctionClass::FunctionClass()
    {
    }
    void FunctionClass::workdone()
    {    qDebug()<<"In workdone class";
        // qDebug()<<"FUNCTION CALLED:"<<Q_FUNC_INFO<<endl;
        // qDebug()<<"storedatathread:"<<QThread::currentThreadId()<<endl;
         QThread::sleep(10);
          qDebug()<<"*******************8SUCCESS**************************";
         emit signalofmainclass();
    }
    

    ///////////////////////////////////////////////////////////////////////////////////////////
    header:

    #ifndef MULTICLASS_H
    #define MULTICLASS_H
    #include <QObject>
    #include <functionclass.h>
    class Multiclass :  public QThread
    {
        Q_OBJECT
    public:
        explicit Multiclass();
        signals: void dicomStoreComplete();
    protected :
        void run() override;
    private: FunctionClass *funt;
    public slots:
    };
    #endif // MULTICLASS_H
    
    .cpp:
    #include "multiclass.h"
    Multiclass::Multiclass()
    {
    }
    void Multiclass::run()
    {
     funt = new FunctionClass;
      qDebug()<<"IN multiclass";
      qDebug()<<"WORKER THREAD ID:"<<QThread::currentThreadId()<<endl;
      connect(funt,SIGNAL(signalofmainclass()),this,SIGNAL(dicomStoreComplete()));
      funt->workdone();
    }
    

    ///////////////////////////////////////////////////////////////////////////////////////////

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <functionclass.h>
    #include <QQmlContext>
    #include<QDebug>
    #include <multiclass.h>
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
        qDebug()<<"MAIN THREAD ID:"<<QThread::currentThreadId()<<endl;
        FunctionClass DB;
        Multiclass *task=new Multiclass;
        QQmlApplicationEngine engine;
        QQmlContext *context =engine.rootContext();
        context->setContextProperty("db",task);
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;
        return app.exec();
    }
    

    ////////////////////////////////////////////////////////////////////
    My expectation is when i click 2 times on my screen this statement should execute 2 times with a duration of 10 sec
    But it is not executing twice it is just executing once.
    qDebug()<<"8SUCCESS*****";**
    My QML FILE is:

    import QtQuick 2.6
    import QtQuick.Window 2.2
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        Rectangle
        {id:xyz
        anchors.fill:parent
        color:"RED"
        MouseArea
        {
        anchors.fill:parent
        onClicked:{db.start();xyz.color="GREEN";}
    
        }
        }
    
        Connections
        {
            target:db
            onDicomStoreComplete:{console.log("lunch");}
        }
    }
    

    What is missing in my code?


  • Moderators

    @ashajg said in QThread with Android:
    besides a bunch of other stuff, done do not use Thread::sleep, and it should work.

    QThread::sleep(10);


    edit that should have been don't instead of done



  • @J.Hilk said in QThread with Android:

    Thread::sleep

    Hi ,

    I have added #include<thread> still Thread::sleep is throwing error that Thread is undeclared.


  • Moderators

    @ashajg

    try

    void FunctionClass::workdone()
    {    qDebug()<<"In workdone class";
    
         QTime time; 
         time.start();
         while(time.elapsed() < 10000) {}
    
          qDebug()<<"*******************8SUCCESS**************************";
         emit signalofmainclass();
    }
    

    You're not meant to call QThread::sleep, in Qt. All kinds of strange things happen, when one does it.


    actually what you should rather do is something like this:

    void FunctionClass::workdone()
    {    qDebug()<<"In workdone class";
    
         QTimer::singleShot(10000, this, [=]()->void{
              qDebug()<<"*******************8SUCCESS**************************";
              emit signalofmainclass();
         });
    }
    


  • @J-Hilk

    I tried both things but didn't work.


  • Moderators

    @ashajg
    looking a bit closer at your code.

    You have only one instance of your "multiclass" where you call start on, start calls automatically run, you can't simply call again start when the thread is already running!
    They way you created this makes this currently a one time use only instance/function



  • @J-Hilk

    Ok.
    Can you please suggest what change I should do to sort this issue.


  • Moderators

    @ashajg
    I think subclassing QThread is for your case the wrong solution. It is in fact the wrong one for most cases.
    I would suggest reading through this block post to get an Idea how QThread is supposed to be used most of the time.
    https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

    In your code example I would actually go to QtConcurrent.

    You could mark a function Q_INVOKABLE so you can access it from QML and start a ne QtConCurrent function.
    For example

    //.h
    Q_INVOKABLE void doInParallel();
    
    //actual function
    void myClass:: doInParallel(){
         QtConcurrent::run([=]()->void{
              auto funt = new FunctionClass;
              qDebug()<<"IN multiclass";
              qDebug()<<"WORKER THREAD ID:"<<QThread::currentThreadId()<<endl;
              connect(funt,SIGNAL(signalofmainclass()),this,SIGNAL(dicomStoreComplete()));
              connect(func, &FunctionClass:: signalofmainclass, func, & FunctionClass::deleteLater());//Your previously leaked the function instance, this fixes that.
              funt->workdone();
         });
    }
    
    

    this is untested of course, just food for thought.



  • ok
    I ll try this code in my multiclass file



  • Hi @J-Hilk

    Just want to ask that in order to call run we use start so in my program I am using db.start in my QML.
    For QtConcurrent how we can start run() through qml?


  • Moderators

    @ashajg

    here a working example

    //multiclass
    
    #ifndef MULTICLASS_H
    #define MULTICLASS_H
    
    #include <QObject>
    
    class Multiclass : public QObject
    {
        Q_OBJECT
    public:
        explicit Multiclass(QObject *parent = nullptr);
    
        Q_INVOKABLE void doInParallel();
    
    signals:
        void working(qint64 id, int index);
        void workDone();
    
    };
    
    #endif // MULTICLASS_H
    
    
    //cpp
    #include "multiclass.h"
    
    #include <QtConcurrent>
    
    #include <QDebug>
    
    Multiclass::Multiclass(QObject *parent) : QObject(parent)
    {
        connect(this, &Multiclass::working, this, [=](qint64 id, int index){
            qDebug() << "Thread:" << id << "index" << index;
        });
    }
    
    void Multiclass::doInParallel()
    {
        QtConcurrent::run([=]()->void{
                  qDebug()<<"doParallel";
                  qDebug()<<"WORKER THREAD ID:"<< QThread::currentThreadId()<<endl;
    
                  for(int i(0); i < 0xFFFF; i++){
                      if(i % 1000 == 0)
                          emit working(reinterpret_cast<qint64>(QThread::currentThread()), i);
                      qDebug() << sqrt(i);
                  }
                  emit workDone();
             });
    }
    
    //main.cpp
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    
    
    #include "multiclass.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QGuiApplication app(argc, argv);
    
        Multiclass *backEnd = new Multiclass;
    
        QQmlApplicationEngine engine;
        QQmlContext *context =engine.rootContext();
        context->setContextProperty("BackEnd",backEnd);
    
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
    
    
        if (engine.rootObjects().isEmpty())
            return -1;
    
        return app.exec();
    }
    
    //main.qml
    import QtQuick 2.6
    import QtQuick.Window 2.2
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        Rectangle
        {
            id:xyz
            anchors.fill:parent
            color:"RED"
            MouseArea
            {
                anchors.fill:parent
                onClicked:{
                    BackEnd.doInParallel();
                    xyz.color ="red";
                }
    
            }
        }
    
        Connections
        {
            target:BackEnd
            onWorking: console.log(id, index);
            onWorkDone: {
                xyz.color ="green";
                console.log("Work done");
            }
        }
    }
    


  • Thank you sir @J-Hilk


Log in to reply