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

QSerialPort and QThread



  • Hello everyone!

    I still trying to learn how to use QSerialPort correctly. And I am getting new problems.

    I create QThread in some PARENT class:

        thread = new QThread; // Create QThread
    
        task = new ThreadClass; // CHILD class, in which I have methods for reading and writing data with QSerialPort
    
        task->moveToThread(thread); // Move needed class to created thread
        connect(thread, SIGNAL(started()), task, SLOT(writeData_slot()); // Connect to writeData_slot() method, when I will start the thread
    

    and I have in this PARENT class another method, where I want to start or stop (now there is while cycle for check) the thread:

    if (isConnected)
        {
            thread->start();
        }
        else
        {
            int count = 0;
    
            while (count < 5)
            {
                count++;
                QThread::msleep(1000);
                qDebug("WE ARE HERE!");
            }
        }
    

    In CHILD class (for thread) I have two methods for reading and writing data with QSerialPort:

    void Thread::readyWrite_slot()
    {
        serialPort->write(writeData);
        qDebug("WRITE");
        QThread::msleep(1000);
    }
    
    void Thread::readyRead_slot()
    {
        readData.append(serialPort->readAll());
    
        if (readData.count() == 5)
        {
            readData.clear();
            qDebug("READ");
            emit readyWrite_signal();
        }
    }
    
        connect(serialPort, &QSerialPort::readyRead, this, &Thread::readyRead_slot);
        connect(this, SIGNAL(readyWrite_signal()), SLOT(readyWrite_slot()));
    

    So, I start thread and get data, but when I want to stop getting data, I want to get all data last time, but I can't:

    WRITE
    READ // In CHILD Thread
    WRITE
    READ // In CHILD Thread
    WRITE
    READ // In CHILD Thread
    WRITE
    WE ARE HERE! // Here I want to close CHILD Thread in PARENT class
    WE ARE HERE!
    WE ARE HERE!
    WE ARE HERE!
    WE ARE HERE!
    READ  // But only here I get my last data in CHILD Thread
    WRITE
    READ // 1 WRITE - 1 READ
    WRITE
    READ // 1 WRITE - 1 READ
    WRITE
    READ // 1 WRITE - 1 READ
    WRITE
    READ // 1 WRITE - 1 READ
    

    It means, that thread doesn't work parallel, but it's not true, because I wrote endless while cycle in readyWrite_slot() with message, for example, and got this message together with WE ARE HERE message. Then, my conclusion, I can't get readyRead() signal for some reason, but after cycle with WE ARE HERE message I continue get readyRead() signal. I don't close SerialPort, I just execute while() cycle 5 times and all. After that thread continues to work correctly.

    So, I can't stop correctly my thread, because I can't get last data, but I need it. I don't know what I can do to fix it.

    Hope for your help and advice! Thank you in advance!


  • Lifetime Qt Champion

    @oBOXPOH My first question: why do you need a thread? QSerialPort is asynchronous - there is usually no need for a thread.



  • @jsulm said in QSerialPort and QThread:

    @oBOXPOH My first question: why do you need a thread? QSerialPort is asynchronous - there is usually no need for a thread.

    Because I need to represent my data parallel without losing of control in PARENT class, where I have some buttons, for example.



  • @oBOXPOH
    Don't understand what you mean here. As @jsulm says, QSerialPort is asynchronous, you just don't usually need a thread, why do you need one? If you mean you are passing a parent to your QSerialPort which then goes out of scope taking the port with it, then don't use that parent!



  • @JonB said in QSerialPort and QThread:

    @oBOXPOH
    Don't understand what you mean here. As @jsulm says, QSerialPort is asynchronous, you just don't usually need a thread, why do you need one? If you mean you are passing a parent to your QSerialPort which then goes out of scope taking the port with it, then don't use that parent!

    I can use call to method for writing data instead of creating thread:

    if (isConnected)
        {
            //thread->start();
    
            task->readyWrite_slot();
        }
    

    but then I get only one WRITE message and no more, i.e. I can't reach method for reading.



  • @oBOXPOH
    Then if you have some "ready write" slot you can also write a "ready read" slot, https://doc.qt.io/qt-5/qiodevice.html#readyRead.



  • @JonB said in QSerialPort and QThread:

    @oBOXPOH
    Then if you have some "ready write" slot you can also write a "ready read" slot, https://doc.qt.io/qt-5/qiodevice.html#readyRead.

    See before, I have it.

    void Thread::readyRead_slot()
    {
        readData.append(serialPort->readAll());
    
        if (readData.count() == 5)
        {
            readData.clear();
            qDebug("READ");
            emit readyWrite_signal();
        }
    }
    

    Thread is just class. I don't use it like QThread. And I haven't readyRead() signal.


  • Moderators

    @oBOXPOH said in QSerialPort and QThread:

    Then, my conclusion, I can't get readyRead() signal for some reason

    Yes, of course, you're calling QThread::Sleep all over the place. Every time you call that, no Signals will be processed, until the sleep is over.

    I highly doubt, that you're programming (with Qt) for a micro controller -> do not use QThread::Sleep, at all.



  • @J-Hilk said in QSerialPort and QThread:

    @oBOXPOH said in QSerialPort and QThread:

    Then, my conclusion, I can't get readyRead() signal for some reason

    Yes, of course, you're calling QThread::Sleep all over the place. Every time you call that, no Signals will be processed, until the sleep is over.

    I highly doubt, that you're programming (with Qt) for a micro controller -> do not use QThread::Sleep, at all.

    Oh, it's, I think, really useful answer! Thank you! But can you then, please, tell me what I need to use to make some delay?


  • Moderators

    @oBOXPOH
    That really depends on your situation, but one usually uses QTimer, or more conveniently one of the static single Shot variants for example
    https://doc.qt.io/qt-5/qtimer.html#singleShot



  • @J-Hilk said in QSerialPort and QThread:

    @oBOXPOH
    That really depends on your situation, but one usually uses QTimer, or more conveniently one of the static single Shot variants for example
    https://doc.qt.io/qt-5/qtimer.html#singleShot

    It's really bad, if another good way isn't exists.

    Because developer needs to write such things instead of some sleep string:

    QTimer::singleShot(100, this, SLOT(slot()));
    

    and developer need to create slot() method, where he writes all actions, which he want to execute after 100ms delay. And it's bad, if you want to make delay not in thread, because in thread you can use:

    QThread::currentThread()->msleep(100);
    

    and not in thread - thing before with singleShot() method. I hope, I am wrong.



  • @oBOXPOH
    It's not "bad". Signals/slots/event-driven is a different architectural design from linear "sleep" approach. Many SDKs or languages use this approach these days, it has its advantages.

    Experts may not thank me for mentioning this, but if you really want to you may be able to use a "sleep"-type and still allow signals/slots/events if you use QEventLoop + QTimer in your thread. You'd have to try it.


  • Lifetime Qt Champion

    @oBOXPOH You are using an event driven framework (Qt is not the only one by the way). In such frameworks you should never block the event loop with long lasting loops and sleep() calls. This is simply working against the framework.


Log in to reply