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. Usage of QSerialport in a QThread (Cannot create children for a parent that is in a different thread)

Usage of QSerialport in a QThread (Cannot create children for a parent that is in a different thread)

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 6 Posters 5.1k Views
  • 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.
  • R Offline
    R Offline
    robro
    wrote on last edited by
    #1

    Hello,

    I am trying to access QSerialPort from another thread.
    Sadly even with a queued connection this is not working and I have no clue why.

    In the following you find a minimal working example which fails if a real port is opened.

    I get the following error:
    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QSerialPort(0x2ccdc763b70), parent's thread is QThread(0x2ccd9beac80), current thread is QThread(0xfcff2ff690)

    Thank you very much :-)

    main.cpp:

    #include "mainwindow.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
    
        return a.exec();
    }
    

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QThread>
    
    class Drive;
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
        Drive *port;
    
    signals:
        void signalGetInfo();
    
    public slots:
        void process();
    
    };
    
    #endif // MAINWINDOW_H
    
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "serialCon.h"
    #include <QTimer>
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        QTimer *timer = new QTimer(this);
            connect(timer, SIGNAL(timeout()), this, SLOT(process()));
            timer->start(1000);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::process()
    {
        port = new Drive;
        QThread t2;
        port->moveToThread(&t2);
        t2.start();
    
        connect(this, &MainWindow::signalGetInfo, port, &Drive::connect_device, Qt::QueuedConnection);
        emit signalGetInfo();
    }
    
    

    serialCon.h

    #ifndef SERIALCONNECTION_H
    #define SERIALCONNECTION_H
    
    #include <QSerialPort>
    
    class Drive : public QObject
    {    
        Q_OBJECT
    
    public:
        Drive();
    
    private:
        QSerialPort *device;
    
    public slots:
        bool connect_device();
    };
    
    #endif // SERIALCONNECTION_H
    
    

    serialCon.cpp

    #include "serialCon.h"
    
    Drive::Drive()
    {
        device = new QSerialPort;
    }
    
    bool Drive::connect_device()
    {
            device->setPortName("name");
            device->open(QSerialPort::ReadWrite);
            device->setBaudRate(QSerialPort::Baud115200);
            device->setDataBits(QSerialPort::Data8);
            device->setParity(QSerialPort::NoParity);
            device->setStopBits(QSerialPort::OneStop);
            device->setFlowControl(QSerialPort::NoFlowControl);
        return true;
    }
    
    
    1 Reply Last reply
    1
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by mrjj
      #2

      Hi
      You seems to have killed by scope issue

      void MainWindow::process()
      {
          port = new Drive;
          QThread t2; <<<<< local variable. will die at last }
          port->moveToThread(&t2);
          t2.start();
      
          connect(this, &MainWindow::signalGetInfo, port, &Drive::connect_device, Qt::QueuedConnection);
          emit signalGetInfo();
      } // t2 is gone here
      
      R 1 Reply Last reply
      4
      • mrjjM mrjj

        Hi
        You seems to have killed by scope issue

        void MainWindow::process()
        {
            port = new Drive;
            QThread t2; <<<<< local variable. will die at last }
            port->moveToThread(&t2);
            t2.start();
        
            connect(this, &MainWindow::signalGetInfo, port, &Drive::connect_device, Qt::QueuedConnection);
            emit signalGetInfo();
        } // t2 is gone here
        
        R Offline
        R Offline
        robro
        wrote on last edited by robro
        #3

        @mrjj said in Usage of QSerialport in a QThread (Cannot create children for a parent that is in a different thread):

        Hi
        You seems to have killed by scope issue

        Hi,
        thanks for pointing out this issue!
        I now added the thread as a member variable and changed the timer to single shot.

        The issue is still there.
        The following line leads to the error:

        device->open(QSerialPort::ReadWrite);
        

        The error only occurs if an existing serial port is opened.
        If I put a random string as port name no error is showing up.

        Any ideas?

        J.HilkJ 1 Reply Last reply
        0
        • R robro

          @mrjj said in Usage of QSerialport in a QThread (Cannot create children for a parent that is in a different thread):

          Hi
          You seems to have killed by scope issue

          Hi,
          thanks for pointing out this issue!
          I now added the thread as a member variable and changed the timer to single shot.

          The issue is still there.
          The following line leads to the error:

          device->open(QSerialPort::ReadWrite);
          

          The error only occurs if an existing serial port is opened.
          If I put a random string as port name no error is showing up.

          Any ideas?

          J.HilkJ Offline
          J.HilkJ Offline
          J.Hilk
          Moderators
          wrote on last edited by J.Hilk
          #4

          @robro
          Couple of things,

          first give your Serialport a parent, so it get moved also to the thread

          new QSerialPort(this);

          second
          your QTimer is going to create a new serialport class and thread each second
          you should change that.


          Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


          Q: What's that?
          A: It's blue light.
          Q: What does it do?
          A: It turns blue.

          T 1 Reply Last reply
          5
          • R Offline
            R Offline
            robro
            wrote on last edited by
            #5

            The timer issue I already noticed and changed.

            Thank you all very much!
            Giving it a parent solved it!

            I have to say, you saved my day :-)

            1 Reply Last reply
            2
            • J.HilkJ J.Hilk

              @robro
              Couple of things,

              first give your Serialport a parent, so it get moved also to the thread

              new QSerialPort(this);

              second
              your QTimer is going to create a new serialport class and thread each second
              you should change that.

              T Offline
              T Offline
              Thanh Tung
              wrote on last edited by
              #6

              @J-Hilk
              i have the same problem and i just try to use Qt, so i don't so much
              can you explain more about:

              first give your Serialport a parent, so it get moved also to the thread
              second
              your QTimer is going to create a new serialport class and thread each second
              you should change that

              and how i can do it??
              thank you!!

              aha_1980A J.HilkJ 2 Replies Last reply
              0
              • T Thanh Tung

                @J-Hilk
                i have the same problem and i just try to use Qt, so i don't so much
                can you explain more about:

                first give your Serialport a parent, so it get moved also to the thread
                second
                your QTimer is going to create a new serialport class and thread each second
                you should change that

                and how i can do it??
                thank you!!

                aha_1980A Offline
                aha_1980A Offline
                aha_1980
                Lifetime Qt Champion
                wrote on last edited by
                #7

                @Thanh-Tung why do you need a thread at all?

                just use QSerialPort with signals&slots - and without a thread.

                Regards

                Qt has to stay free or it will die.

                T 1 Reply Last reply
                1
                • aha_1980A aha_1980

                  @Thanh-Tung why do you need a thread at all?

                  just use QSerialPort with signals&slots - and without a thread.

                  Regards

                  T Offline
                  T Offline
                  Thanh Tung
                  wrote on last edited by
                  #8

                  @aha_1980 i need thread because i have a button1 that will run a while loop to communicate with device through serial port, and button2 that will run a another thread( this thread also use serial port, so a need kill the thread of button 1).

                  aha_1980A 1 Reply Last reply
                  0
                  • T Thanh Tung

                    @aha_1980 i need thread because i have a button1 that will run a while loop to communicate with device through serial port, and button2 that will run a another thread( this thread also use serial port, so a need kill the thread of button 1).

                    aha_1980A Offline
                    aha_1980A Offline
                    aha_1980
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    @Thanh-Tung said in Usage of QSerialport in a QThread (Cannot create children for a parent that is in a different thread):

                    i have a button1 that will run a while loop to communicate with device through serial port, and button2 that will run a another thread( this thread also use serial port, so a need kill the thread of button 1).

                    That sounds like a horrible design - you should overthink it.

                    As said, you don't need threads, as QSerialPort is asynchronous. Just use the signals bytesWritten and readyRead. See for example here: https://doc.qt.io/qt-5/qtserialport-terminal-example.html

                    Regards

                    Qt has to stay free or it will die.

                    1 Reply Last reply
                    3
                    • T Thanh Tung

                      @J-Hilk
                      i have the same problem and i just try to use Qt, so i don't so much
                      can you explain more about:

                      first give your Serialport a parent, so it get moved also to the thread
                      second
                      your QTimer is going to create a new serialport class and thread each second
                      you should change that

                      and how i can do it??
                      thank you!!

                      J.HilkJ Offline
                      J.HilkJ Offline
                      J.Hilk
                      Moderators
                      wrote on last edited by
                      #10

                      hello @Thanh-Tung and welcome.

                      @Thanh-Tung said in Usage of QSerialport in a QThread (Cannot create children for a parent that is in a different thread):

                      @J-Hilk
                      i have the same problem and i just try to use Qt, so i don't so much
                      can you explain more about:

                      first give your Serialport a parent, so it get moved also to the thread
                      second

                      Here is the thing, if you don't know what the parent child relationship in Qt is, you should not attempt using multiple threads. IMHO.

                      Take a look at the documentation:
                      https://doc.qt.io/qt-5/qtcore-index.html
                      and especially
                      https://doc.qt.io/qt-5/objecttrees.html

                      your QTimer is going to create a new serialport class and thread each second
                      you should change that

                      and how i can do it??
                      thank you!!

                      You need to freshen up your C++ knowledge! Are you new to programming in general ?

                      new is a key word in almost all programming languages - that I use/know of at least - that indicates a the. creation of a new object.
                      https://en.cppreference.com/w/cpp/language/new

                      So when you new an object (QSerialPort in this case) the object is created and the pointer is stored in a variable, in this example.
                      BUT just because you assign a new object to the old variable does not mean that the old object is destroyed!!! In fact it's still there, taking up memory.
                      Or worse, in your case where you have infinite while loops running, its not only taking up memory but cpu time as well, keeping the os busy with thread swapping and consumes electricity. DON'T do it!

                      c++ does not have fancy garbage collectors like python/JS etc. YOU have to manage your own garbage!

                      To get back to your question:
                      @robro wrote:

                      QTimer *timer = new QTimer(this);
                              connect(timer, SIGNAL(timeout()), this, SLOT(process()));
                              timer->start(1000);
                      
                      ....
                      void MainWindow::process()
                      {
                          port = new Drive;
                          QThread t2;
                          port->moveToThread(&t2);
                          t2.start();
                      
                          connect(this, &MainWindow::signalGetInfo, port, &Drive::connect_device, Qt::QueuedConnection);
                          emit signalGetInfo();
                      }
                      

                      timer is QTimer object that is created on start up of the class and will call every 1000ms the slot process -> each second port = new Drive; is executed -> each second a new Drive instance is created and the old one not deleted.

                      If you're not running a microcontroller, but have an over arching operating system than there is no reason to not use the asynchronous api of QSerialPort.

                      I still have hope that the synchronous api will be removed in Qt6. @aha_1980 please make it happen 😉🙏


                      Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                      Q: What's that?
                      A: It's blue light.
                      Q: What does it do?
                      A: It turns blue.

                      A 1 Reply Last reply
                      4
                      • J.HilkJ J.Hilk

                        hello @Thanh-Tung and welcome.

                        @Thanh-Tung said in Usage of QSerialport in a QThread (Cannot create children for a parent that is in a different thread):

                        @J-Hilk
                        i have the same problem and i just try to use Qt, so i don't so much
                        can you explain more about:

                        first give your Serialport a parent, so it get moved also to the thread
                        second

                        Here is the thing, if you don't know what the parent child relationship in Qt is, you should not attempt using multiple threads. IMHO.

                        Take a look at the documentation:
                        https://doc.qt.io/qt-5/qtcore-index.html
                        and especially
                        https://doc.qt.io/qt-5/objecttrees.html

                        your QTimer is going to create a new serialport class and thread each second
                        you should change that

                        and how i can do it??
                        thank you!!

                        You need to freshen up your C++ knowledge! Are you new to programming in general ?

                        new is a key word in almost all programming languages - that I use/know of at least - that indicates a the. creation of a new object.
                        https://en.cppreference.com/w/cpp/language/new

                        So when you new an object (QSerialPort in this case) the object is created and the pointer is stored in a variable, in this example.
                        BUT just because you assign a new object to the old variable does not mean that the old object is destroyed!!! In fact it's still there, taking up memory.
                        Or worse, in your case where you have infinite while loops running, its not only taking up memory but cpu time as well, keeping the os busy with thread swapping and consumes electricity. DON'T do it!

                        c++ does not have fancy garbage collectors like python/JS etc. YOU have to manage your own garbage!

                        To get back to your question:
                        @robro wrote:

                        QTimer *timer = new QTimer(this);
                                connect(timer, SIGNAL(timeout()), this, SLOT(process()));
                                timer->start(1000);
                        
                        ....
                        void MainWindow::process()
                        {
                            port = new Drive;
                            QThread t2;
                            port->moveToThread(&t2);
                            t2.start();
                        
                            connect(this, &MainWindow::signalGetInfo, port, &Drive::connect_device, Qt::QueuedConnection);
                            emit signalGetInfo();
                        }
                        

                        timer is QTimer object that is created on start up of the class and will call every 1000ms the slot process -> each second port = new Drive; is executed -> each second a new Drive instance is created and the old one not deleted.

                        If you're not running a microcontroller, but have an over arching operating system than there is no reason to not use the asynchronous api of QSerialPort.

                        I still have hope that the synchronous api will be removed in Qt6. @aha_1980 please make it happen 😉🙏

                        A Offline
                        A Offline
                        Astrinus
                        wrote on last edited by
                        #11

                        @J-Hilk said in Usage of QSerialport in a QThread (Cannot create children for a parent that is in a different thread):

                        If you're not running a microcontroller, but have an over arching operating system than there is no reason to not use the asynchronous api of QSerialPort.

                        And if you are running onto a microcontroller and you are not bitbanging, you'd better implement an asynchronous interface to the serial port anyway ;-)

                        I still have hope that the synchronous api will be removed in Qt6. @aha_1980 please make it happen 😉🙏

                        Another vote!

                        1 Reply Last reply
                        0
                        • T Offline
                          T Offline
                          Thanh Tung
                          wrote on last edited by
                          #12

                          @aha_1980
                          Thanks for your advice, i may overthink about it, and now i use the Qtimer instead Qthread.
                          @J-Hilk
                          i usually use C and this is the first project i use C++ and Qt :)))
                          thanks you so much for your help and all your recommendation!!!

                          1 Reply Last reply
                          3

                          • Login

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