Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Not getting past emit command.
Forum Updated to NodeBB v4.3 + New Features

Not getting past emit command.

Scheduled Pinned Locked Moved General and Desktop
12 Posts 2 Posters 2.8k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    achmed
    wrote on last edited by
    #1

    I have a 3rd party library that im using to run tests on external hardware.
    Testing takes 10sec, and during this time the window freezes.
    I Have done some reading and moved the 3rd party code to a separate thread to try and prevent the window freeze.
    I send a signal from the main thread to the 3rd party code running in a separate thread to start testing.
    While the code is executing in the separate thread my main thread should continue to process input events in a while loop, like a Pause button being clicked. Events must be checked until the 3rd party code emits a signal to the main thread telling it that the results are available. Problem is my MainWindow is still freezing and the While loop is only executed when the 3rd party code has finished and results are available. Why is the code not passing the 1st emit statement and continuing with the while loop?

    @#ifndef MAINWINDOW_H
    #define MAINWINDOW_H

    #include <QMainWindow>
    #include <QEventLoop>
    #include <iostream>

    #include "mythreadclass.h"

    namespace Ui {
    class MainWindow;
    }

    class MainWindow : public QMainWindow
    {
    Q_OBJECT

    public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    private slots:
    void on_StartButton_clicked();
    void on_PauseButton_clicked();
    void ReceiveResults(int NewValue);

    private:
    Ui::MainWindow *ui;
    MyThreadClass *MyThreadObj;
    QEventLoop *EventLoopObj;
    int Result;

    signals:
    void StartTest();

    };

    #endif // MAINWINDOW_H
    @

    @#include "mainwindow.h"
    #include "ui_mainwindow.h"

    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);

    EventLoopObj = new QEventLoop(parent);
    MyThreadObj = new MyThreadClass();
    
    connect(this, SIGNAL(StartTest()), MyThreadObj, SLOT(DoTest()));
    connect(MyThreadObj, SIGNAL(SendResult(int)), this, SLOT(ReceiveResults(int)));
    

    }

    MainWindow::~MainWindow()
    {
    delete ui;
    MyThreadObj->deleteLater();
    EventLoopObj->deleteLater();
    }

    void MainWindow::on_StartButton_clicked()
    {
    MyThreadObj->start();
    Result = 0;

    emit StartTest(); //Problem - code execution stopes here until 3rd party command has finished executing.
    
    qDebug("Emit Done");
    
    while(Result == 0)
    {
        EventLoopObj->processEvents();
    }
    
    ui->label->setText("Test Done");
    MyThreadObj->quit();
    

    }

    void MainWindow::on_PauseButton_clicked()
    {
    ui->Pause_Label->setText("Paused");
    }

    void MainWindow::ReceiveResults(int NewValue)
    {
    Result = NewValue;
    }
    @

    @#ifndef MYTHREADCLASS_H
    #define MYTHREADCLASS_H

    #include <QObject>
    #include <QThread>
    #include "waitclass.h" //Simulates 3rd party library

    class MyThreadClass : public QThread
    {
    Q_OBJECT
    private:
    WaitClass *WaitObj; //Simulates 3rd party varable
    public:
    explicit MyThreadClass(QObject *parent = 0);
    ~MyThreadClass();

    void run();
    

    signals:
    void SendResult(int NewValue);

    public slots:
    void DoTest();

    };

    #endif // MYTHREADCLASS_H
    @

    @#include "mythreadclass.h"

    MyThreadClass::MyThreadClass(QObject *parent)
    {
    WaitObj = new WaitClass();
    }

    MyThreadClass::~MyThreadClass()
    {
    WaitObj.deleteLater();
    }

    void MyThreadClass::run()
    {
    exec();
    }

    void MyThreadClass::DoTest()
    {
    WaitObj->WaitSec(10); //Simulates 3rd party command that takes 10sec to finish
    int SimulatedResult = 255; //Simulates value returned by 3rd party command

    emit SendResult(SimulatedResult);
    

    }
    @

    1 Reply Last reply
    0
    • A Offline
      A Offline
      andre
      wrote on last edited by
      #2

      You clearly have not done enough reading on the matter.

      In this scenario, you should not subclass QThread. Instead, use a worker object and move that to a thread managed by a (vanilla) QThread.

      The root of your problem is that you have created a slot on the manager of your thread (the QThread object), but that manager itself lives in the thread that created it in the first place.

      There is lots of information to be found on this issue, including in the QThread documentation itself.

      1 Reply Last reply
      0
      • A Offline
        A Offline
        achmed
        wrote on last edited by
        #3

        My Original approach was like you stated to move the worker object to a vanilla QThread. But then I ended up having other issues and compiling errors. People told me that the errors where caused because the object was not created in the 2nd thread where the worker object was moved to. I Will try it again and let you know what happens.

        1 Reply Last reply
        0
        • A Offline
          A Offline
          achmed
          wrote on last edited by
          #4

          Ok. The above code was just an example of the issue I was facing in another bigger program. I Rewrote the code back to the way It was, where I try moving the objects to a vanilla QThread. I Get the same two errors as before.

          On first run I usually get:

          @QObject: Cannot create children for a parent that is in a different thread.
          (Parent is QSerialPort(0xb1fc20), parent's thread is QThread(0x15819a70), current thread is QThread(0xb30d50)
          QObject: Cannot create children for a parent that is in a different thread.
          (Parent is QSerialPort(0xb1fc38), parent's thread is QThread(0x15819a70), current thread is QThread(0xb30d50)@

          on second run I sometimes get this error:
          @Invalid parameter passed to C runtime function.
          ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 16e80d50. Receiver 'MainWindowWindow' (of type 'QWidgetWindow') was created in thread 154b9a70", file kernel\qcoreapplication.cpp, line 521
          Invalid parameter passed to C runtime function.
          QObject::killTimers: timers cannot be stopped from another thread
          X:\MTEK\Programming\Contact Noise GUI\43\build-Contact_Noise-Desktop_Qt_5_3_MinGW_32bit-Debug\debug\Contact_Noise.exe exited with code 3@

          I Will post some of my code in the next couple of minutes.

          1 Reply Last reply
          0
          • A Offline
            A Offline
            achmed
            wrote on last edited by
            #5

            I have omitted code that I think might be unnecessary.

            @class MainWindow : public QMainWindow
            {
            Q_OBJECT

            public:
            bool TestActive;
            bool ProcessEvents;
            QEventLoop *EventLoopObj;

            QThread *TestThreadObj;
            TestClass *TestObj;
            
            RelayClass *RelayObj;
            
            ScopeClass *ScopeObj;
            
            MotorClass *MotorObj;
            
            explicit MainWindow(QWidget *parent = 0);
            ~MainWindow();
            
            void Initialize();
            void Uninitialize();
            

            public slots:
            void on_StartBtn_clicked();

            void SLOT_StopEventProcessing();
            

            signals:
            void SIGNAL_StartTest();

            };@

            @MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
            {
            EventLoopObj = new QEventLoop(parent);

            TestThreadObj = new QThread();
            TestObj = new TestClass();
            
            RelayObj = new RelayClass();
            
            ScopeObj = new ScopeClass();
            
            MotorObj = new MotorClass();
            

            }

            MainWindow::~MainWindow()
            {
            EventLoopObj->deleteLater();

            MotorObj->deleteLater();
            
            ScopeObj->deleteLater();
            
            RelayObj->deleteLater();
            
            TestThreadObj->deleteLater();
            TestObj->deleteLater();
            

            }

            void MainWindow::Initialize()
            {
            //START THREAD OBJs
            TestThreadObj->start();

            //MOVE OBJECTS TO THREADS
            TestObj->moveToThread(TestThreadObj);
            ScopeObj->moveToThread(TestThreadObj); 
            MotorObj->moveToThread(TestThreadObj); 
            RelayObj->moveToThread(TestThreadObj); 
            
            //SET TEST OBJ
            TestObj->Initialize();
            
            //SET RELAY OBJ
            RelayObj->setPort(ui->Relay_Com->text());
            RelayObj->Initialize();
            
            //SET SCOPE OBJ
            ScopeObj->Initialize();
            
            //SET MOTOR OBJ
            MotorObj->SetPort(ui->Motor_Com->text()); //Merge with Initialize
            MotorObj->Initialize();
            
            //CONNECT UI OBJ
            connect(this, SIGNAL(SIGNAL_StartTest()), TestObj,SLOT(StartTest())); 
            connect(TestObj, SIGNAL(TestingDone()), this, SLOT(SLOT_StopEventProcessing())); 
            
            //CONNECT RELAY OBJ
            connect(TestObj, SIGNAL(SIGNAL_AllRelaysOff()), RelayObj, SLOT(RelaysAllOff()));
            connect(TestObj, SIGNAL(SIGNAL_RelayOn(int)), RelayObj, SLOT(RelayOn(int)));
            
            //CONNECT SCOPE OBJ
            connect(TestObj, SIGNAL(SIGNAL_SCOPE_Initialize()), ScopeObj, SLOT(Initialize()));
            connect(TestObj, SIGNAL(SIGNAL_SCOPE_MeasureVavg()), ScopeObj, SLOT(TestVavg()));
            connect(TestObj, SIGNAL(SIGNAL_SCOPE_MeasureVpp()), ScopeObj, SLOT(TestVpp()));
            connect(TestObj, SIGNAL(SIGNAL_SCOPE_MeasureVrms()), ScopeObj, SLOT(TestVrms()));
            
            //CONNECT MOTOR  OBJECT
            connect(TestObj, SIGNAL(SIGNAL_RunMotor()), MotorObj, SLOT(RunMotor()));
            
            TestActive = true;
            ProcessEvents =true;
            

            }

            void MainWindow::Uninitialize()
            {
            MotorObj->Uninitialize();

            ScopeObj->Uninitialize();
            
            RelayObj->Uninitialize();
            
            TestObj->Uninitialize();
            
            TestThreadObj->quit();
            

            }

            void MainWindow::on_StartBtn_clicked()
            {
            Initialize();
            emit SIGNAL_StartTest();
            while(ProcessEvents == true)
            {
            EventLoopObj->processEvents();
            }
            Uninitialize();
            }

            void MainWindow::SLOT_StopEventProcessing()
            {
            ProcessEvents = false;
            }
            @

            Inside the MotorObj and RelayObj there are QSerialPort variables.
            QSerialPort* ComPort = new (QSerialPort);
            From what I have read and understand this is where things go wrong.
            The QSerialPorts Object seems to be running in the wrong thread.
            I Have also tried to move the ComPort Objects contained in both MotorObj and RelayObj to the TestThread. When I do so The application Freezes when I click on the Start Button @MotorObj->ComPort->moveToThread(TestThreadObj);@

            1 Reply Last reply
            0
            • A Offline
              A Offline
              andre
              wrote on last edited by
              #6

              I have not studied the complete code sample yet. But does it help if you just create your QSerialPort object with the parent in the first place? QObject::moveToThread also moves all child objects, so that should work. If moving QSerialPort keeps given trouble, I suggest you only create it after the move from within the right thread.

              1 Reply Last reply
              0
              • A Offline
                A Offline
                achmed
                wrote on last edited by
                #7

                Ok. I Will get back to you. Thanks for your help.

                1 Reply Last reply
                0
                • A Offline
                  A Offline
                  achmed
                  wrote on last edited by
                  #8

                  Looks like there was noting wrong with my initial approch by moving the objects to a Vanilla QThread. I Have managed to traced down the problem a bit more. I Think the warnings are a bit misleading. Below is the code for the RelayObj. If I comment out the "relays->write()" lines the errors disappear. Also If I create other objects in a similar way in the RelayClass like I do with QSerialPort I don't get any errors at all. Meaning it must be something to do with QSerialPort and how it behaves in a Threaded environment.

                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    achmed
                    wrote on last edited by
                    #9

                    @#include "relayclass.h"

                    RelayClass::RelayClass(QObject *parent) : QObject(parent)
                    {
                    relays = new (QSerialPort);
                    }

                    RelayClass::~RelayClass()
                    {
                    relays->deleteLater();
                    }

                    void RelayClass::Initialize()
                    {
                    relays->setPortName(COM);

                    if(relays->open(QIODevice::ReadWrite))
                    {
                        relays->setBaudRate(QSerialPort::Baud9600);
                        relays->setDataBits(QSerialPort::Data8);
                        relays->setParity(QSerialPort::NoParity);
                        relays->setStopBits(QSerialPort::OneStop);
                        relays->setFlowControl(QSerialPort::NoFlowControl);
                    }
                    

                    }

                    void RelayClass::Uninitialize()
                    {
                    //relays->close();
                    }

                    void RelayClass::RelaysAllOff()
                    {
                    relay_arr.clear();
                    relay_arr = "all_offx";
                    //relays->write(relay_arr); //Causes Error
                    relays->waitForBytesWritten(-1);
                    }

                    void RelayClass::RelayOn(int Ch_on)
                    {
                    relay_arr.clear();
                    relay_arr.setNum(Ch_on);
                    relay_arr.prepend("ch");
                    relay_arr.append("_onx");
                    //relays->write(relay_arr); //Causes Error
                    relays->waitForBytesWritten(-1);
                    }

                    void RelayClass::setPort(QString PORT)
                    {
                    COM = PORT;
                    }
                    @

                    1 Reply Last reply
                    0
                    • A Offline
                      A Offline
                      achmed
                      wrote on last edited by
                      #10

                      @#ifndef RELAYCLASS_H
                      #define RELAYCLASS_H

                      #include <QObject>
                      #include <QtSerialPort>
                      #include <QString>

                      #include "waitclass.h"

                      class RelayClass : public QObject
                      {
                      Q_OBJECT
                      public:
                      QString COM;
                      QByteArray relay_arr;
                      QSerialPort *relays;

                      WaitClass *WaitObj;
                      
                      explicit RelayClass(QObject *parent=0);
                      ~RelayClass();
                      
                      void Initialize();
                      void Uninitialize();
                      

                      public slots:
                      void RelaysAllOff();
                      void RelayOn(int Ch_on);
                      void setPort(QString PORT);
                      };

                      #endif // RELAYCLASS_H
                      @

                      1 Reply Last reply
                      0
                      • A Offline
                        A Offline
                        achmed
                        wrote on last edited by
                        #11

                        Looks like this article may have the answer to my problems.
                        "LINK":http://stackoverflow.com/questions/23559610/how-to-setup-qserialport-on-a-separate-thread

                        1 Reply Last reply
                        0
                        • A Offline
                          A Offline
                          achmed
                          wrote on last edited by
                          #12

                          Ok. Problem solved.
                          I Moved the QSerialPort variables to my main thread and now use Signals and Slots to send data to them. I'm not an expert on this, and just quoting what I have read. QSerialPort already provides you non-blocking mechanism for your GUI application. When moving QSeerial Port to another thread this somehow interferes with the way objects communicate between one another and that is where the errors are coming from. If anyone has some extra opinions on this or knows how to move a QSerialPort object into a separate thread, please do share.

                          1 Reply Last reply
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved