Thread that read from QSerialPort



  • Hi,

    i'm developing an application that use QSerialPort.
    I made two threads , one to read and one to write on the serial port.
    I would like to know if i'm doing right..
    this is the implementation of the Rx thread:

    • in the run() function i only inserted a

    @while(!end)
    {
    sleep(1)
    }
    @

    while in the thread declaration i inserted:

    @connect(serialPort, SIGNAL(readyRead()), this, SLOT(ReadFromSerialPort()));@

    So that when there is something on the serial port it calls the ReadFromSerialPort functions.

    Is that the correct way to do? Or i need to remove the signal/slot and insert something in the while(!end) loop to check if there is something to read?

    Thanks,
    Riccardo



  • That is probably not the most efficient way of doing this. QSerialPort can be used either synchronously or asynchronously.

    Synchronously: use waitForReadyRead or waitForBytesWritten, but this will block your thread until either data is received or written. This is bad if you use it in the GUI thread (i.e. the main Qt thread): your application will not respond to user input until the read or write is done.

    Asynchronously: uses signal and slots. In this case you connect to the readyRead signal with your slot (ReadFromSerialPort), and each time data is available the signal will be emitted and your slot will be executed. Now you don't need to wait in a wasteful while loop for data reads or writes + no need for extra threads.
    For more information how this is done internally check:
    https://qt-project.org/wiki/Threads_Events_QObjects#285a62c361be4793a6c10d04e3823a80

    I highly recommend using the second approach, especially if you plan to use more Qt.


  • Moderators

    Hi,

    [quote author="rileo8" date="1383151640"]
    @while(!end)
    {
    sleep(1)
    }
    @
    [/quote]This is an infinite loop. It blocks the event loop, which means your thread can't receive any signals.

    How fast is your read/write rate? You might not even need separate threads. See this "official example":http://qt-project.org/doc/qt-5.1/qtserialport/terminal.html -- the QSerialPort lives in the main thread itself.



  • Hi,

    the problem is that i'm developing an application that communicate with an external interface with the serial port so it continuosly communicate with it while the GUI need to be responsive and accept user input/show values etc...

    So i want to separate read/write from serial port AND the GUI

    What you suggest to do?



  • Reading the documentation i found that maybe i have to substitute

    @while(!end)
    {
    sleep(1)
    }@

    whit @exec()@

    that enters the event loop and waits until exit() is calle

    Is it correct?

    Thanks



  • No it is not correct. You don't need a wait loop like that.


  • Moderators

    [quote author="rileo8" date="1383208867"]that enters the event loop and waits until exit() is calle

    Is it correct?[/quote]Yes, it's correct :)

    Next, read the "Thread Affinity" section of the "QObject documentation":http://doc-snapshot.qt-project.org/qt5-stable/qobject.html#thread-affinity -- it explains how to choose the thread to run your slots.

    [quote author="t3685" date="1383215445"]No it is not correct. You don't need a wait loop like that.[/quote]rileo8 realized that after reading the documentation. That's why he asked if it's correct to replace the wait loop with exec().



  • Ok,

    i'm understanding that i hadn;t understand qthreads before... :-)
    The question is :

    i need a "worker" thread that read and write from a serial port so i can use this approach:

    class Worker : public QObject
    {
    Q_OBJECT
    private slots:
    void onTimeout()
    {
    qDebug()<<"Worker::onTimeout get called from?: "<<QThread::currentThreadId();
    }
    };

    @class Thread : public QThread
    {
    Q_OBJECT

    private:
    void run()
    {
    qDebug()<<"From work thread: "<<currentThreadId();
    QTimer timer;
    Worker worker;
    connect(&timer, SIGNAL(timeout()), &worker, SLOT(onTimeout()));
    timer.start(1000);

        exec&#40;&#41;;
    }
    

    };@

    the problem is...if i need that the worker thread receive signals from the GUI what i have to do? Connect with signal&slot the GUI withe theThread class and then connect always with signals/slot the thread calls with the worker class?


  • Moderators

    To make things simple, you don't need to subclass QThread. Just have the timer in your worker:

    @
    class Worker : public QObject
    {
    Q_OBJECT
    QTimer* timer;

    public:
    Worker(QObject *parent = 0) : QObject(parent) {
    // Worker must be parent of QTimer
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout()));
    }

    public slots:
    void startWorking() { timer->start(1000); }

    private slots:
    void onTimeout() {...}
    };
    @

    @
    int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    QThread thread;
    Worker worker;

    QObject::connect(&thread, SIGNAL(started()),
            &worker, SLOT(startWorking()));
    
    worker.moveToThread(&thread);
    thread.start();
    
    int returnValue = a.exec&#40;&#41;;
    thread.wait(&#41;;
    return returnValue;
    

    }
    @

    You can connect signals and slots directly between your worker and your GUI.



  • Ok perfect,thanks to everybody for the help!
    Now i better understand Qthreads...


  • Moderators

    You're welcome.

    Good luck with your project!



  • Hi, i'm stille here with another question..

    now my code loooks like this:

    @#include "mainwindow.h"
    #include <QtGui/QApplication>
    #include <QThread>

    #include "executer.h"
    #include "checker.h"
    #include "networker.h"

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    MainWindow w;
    w.showMaximized();

    Checker checker;
    Networker networker;
    Executer executer;

    QThread checkerThread;
    QThread networkerThread;
    QThread executerThread;

    QObject::connect(&executerThread,SIGNAL(started()),&executer,SLOT(Start()));

    checker.moveToThread(&checkerThread);
    networker.moveToThread(&networkerThread);
    executer.moveToThread(&executerThread);

    checkerThread.start();
    networkerThread.start();
    executerThread.start();

    int returnValue=a.exec();

    executerThread.wait();

    return returnValue;

    }
    @

    i neew to share an object (of a custom Configuration type) between all trheads.

    Is it coorect to declare it in the main, pass it to all htreads and also share a mutex so that every thread lock and unlock it?

    Thanks


  • Moderators

    If it is not a QObject, then yes you can do that.

    If it is a QObject, then you are not allowed to share it between threads. QObject is not thread-safe.

    See this page for info on how to share data between threads: http://doc-snapshot.qt-project.org/qt5-stable/threads-synchronizing.html



  • [quote author="JKSH" date="1383215991"][quote author="rileo8" date="1383208867"]that enters the event loop and waits until exit() is calle

    Is it correct?[/quote]Yes, it's correct :)

    Next, read the "Thread Affinity" section of the "QObject documentation":http://doc-snapshot.qt-project.org/qt5-stable/qobject.html#thread-affinity -- it explains how to choose the thread to run your slots.

    [quote author="t3685" date="1383215445"]No it is not correct. You don't need a wait loop like that.[/quote]rileo8 realized that after reading the documentation. That's why he asked if it's correct to replace the wait loop with exec().[/quote]

    The QSerialPort class is asynchronous. You don't need threads to do this.



  • It is not a QObject, is a simple c++ custom class


  • Moderators

    [quote author="t3685" date="1383225223"]The QSerialPort class is asynchronous. You don't need threads to do this.[/quote]Yes, if I/O is slow enough, then no threads are needed. That's why I asked about the read/write rate.



  • Yes i understood this,
    infact now i have:

    GUI thread
    thread for operations on serialport 1
    thread for operations on serialport 2
    thread for network operations

    Now i also added a custom Configuration class that is share d between threads with a shared QMutex to enable access to it



  • [quote author="JKSH" date="1383225543"][quote author="t3685" date="1383225223"]The QSerialPort class is asynchronous. You don't need threads to do this.[/quote]Yes, if I/O is slow enough, then no threads are needed. That's why I asked about the read/write rate.[/quote]

    The write function returns immediately. The readyRead() signal is only emitted when data is available. I don't think it matters then what the Baud rate is.

    http://qt-project.org/doc/qt-5.1/qtserialport/terminal.html


  • Moderators

    [quote author="t3685" date="1383225815"]
    The write function returns immediately. The readyRead() signal is only emitted when data is available. I don't think it matters then what the Baud rate is.[/quote]Sorry for being unclear; I meant the rate at which read() and write() need to be called (relative to other operations). An active thread will experience jitter, especially on a non-real-time OS. That raises the possibility of a buffer becoming empty. Depending on how the devices have been designed, an empty write buffer could kill the entire connection.

    t3685 has a very valid point though. rileo8, try running your workers in the main thread first using the asynchronous API, and see how your program performs. You might not need 3 extra threads.



  • Hi,

    my point is that i need to accomplish different operations on 2 serial ports and also network operations so i think that putting all i t he gui can cause gui freezing...



  • Hi guys,

    the main point to use QtSerialPort's objects in different thread - a bug with the stopping of I/O at moving window or expanding window. Of course, this problem only in Windows OS. :)

    [quote]

    GUI thread

    thread for operations on serialport 1

    thread for operations on serialport 2

    thread for network operations

    [/quote]

    IMHO, it is better:

    1. GUI thread

    2. thread for operations on serialport 1, serialport 2, network


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.