3

hi I have a problem with updating ui by a thread. code works correctly but the problem is when I want to move my window as you know in that moment ui thread will stop updating. and my thread sends values to stopped thread that causes error. I don't know how to fix this.

here is my thread code header:

#ifndef READERTHREAD_H
#define READERTHREAD_H
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QThread>

class readerThread : public QThread
{
    Q_OBJECT
public:
    explicit readerThread(QObject *parent = 0);
    void run();
    bool stop = false;
    QByteArray port_input;
    QByteArray payload;
    quint8 starter_symbol = 0;
    quint8 message_length = 0;
    quint8 message_ID = 0;
    readerThread *thread;
signals:
    void updated(QByteArray , quint8);

private:
    QSerialPort *serial;

};

#endif // READERTHREAD_H

my thread .cpp:

#include "readerthread.h"
#include <QtCore>

readerThread::readerThread(QObject *parent) :
    QThread(parent)
{

    serial = new QSerialPort(this);

    foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts())
    serial->setPortName(serialPortInfo.portName());

    serial->setBaudRate(QSerialPort::Baud115200);

    serial->setDataBits(QSerialPort::Data8);

    serial->setParity(QSerialPort::NoParity);

    serial->setFlowControl(QSerialPort::NoFlowControl);

    serial->setStopBits(QSerialPort::OneStop);

//    serial->setReadBufferSize(8192);

    serial->open(QIODevice::ReadOnly);

    serial->errorString();

}

void readerThread::run()
{
    while(serial->isOpen())
    {
        port_input.append(serial->readAll());
        if(port_input.count() >= 150)
        {
           starter_symbol = port_input.indexOf(254);
           if((port_input.at(starter_symbol + 3) == 01) && (port_input.at(starter_symbol + 4) == 01))
           {
              message_length = port_input.at(starter_symbol + 1);
              message_ID = port_input.at(starter_symbol + 5);
              payload = port_input.mid(starter_symbol + 6 , message_length);
              port_input.remove(starter_symbol , message_length + 8);
              emit updated(payload , message_ID);
           }
           port_input.remove(0 , starter_symbol);
        }
    }
}

and here my mainwindow.cpp in short :

   struct mavlink_attitude_t
        {
            /// <summary> Timestamp (milliseconds since system boot) </summary>
              quint32 time_boot_ms;
                /// <summary> Roll angle (rad, -pi..+pi) </summary>
              float roll;
                /// <summary> Pitch angle (rad, -pi..+pi) </summary>
              float pitch;
                /// <summary> Yaw angle (rad, -pi..+pi) </summary>
              float yaw;
                /// <summary> Roll angular speed (rad/s) </summary>
              float rollspeed;
                /// <summary> Pitch angular speed (rad/s) </summary>
              float pitchspeed;
                /// <summary> Yaw angular speed (rad/s) </summary>
              float yawspeed;

        };

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        thread = new readerThread(this);
        connect(thread , SIGNAL(updated(QByteArray,quint8)) , this , SLOT(onUpdate(QByteArray,quint8)));
        thread->start();

    }

        void MainWindow::onUpdate(QByteArray payload , quint8 ID)
        {
               mavlink_attitude_t data;
               memcpy(&data,payload.data(),sizeof(mavlink_attitude_t));
               ui->timebootms->setText(QString::number(data.time_boot_ms));
               ui->roll->setText(QString::number(data.roll));
               ui->pitch->setText(QString::number(data.pitch));
               ui->yaw->setText(QString::number(data.yaw));
               ui->rollspeed->setText(QString::number(data.rollspeed));
               ui->pitchspeed->setText(QString::number(data.pitchspeed));
               ui->yawspeed->setText(QString::number(data.yawspeed));
        }
László Papp
  • 51,870
  • 39
  • 111
  • 135
  • You could try forcing the connection to be Qt::QueuedConnection (which should be already done automatically). Not sure if your thread signaling will be fine without event loop. One could try to create an threadobject running in native QThread (signal slot support) or just use a QtConcurrent – Sebastian Lange Nov 13 '14 at 10:30
  • thank you for your time. what you mean by without event loop? –  Nov 13 '14 at 10:45
  • your `connect` has default last argument (`Qt::AutoConnection`). This means that `onUpdate` is invoked on main thread (window is assigned to main thread). So please verify that you are sure what is the source of problems. – Marek R Nov 13 '14 at 11:17
  • 1
    you should also read this: http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/ – Marek R Nov 13 '14 at 11:19
  • thank you @Mark R for your time and yes I'm sure the problem is what I said. I'm wonder if there is any way to pause a thread in some condition and resume it after that? –  Nov 13 '14 at 14:00
  • @HamedBB Not sure what you mean with "pause". Do you mean like in the middle of your while loop? Or just check if it should be paused at the beginning of your while loop? – thuga Nov 14 '14 at 07:42
  • @thuga I mean in middle of the while loop but I think it's imposible. I don't know how to fix this problem! I tried almost everything! –  Nov 14 '14 at 08:59
  • You could use a flag that you could check but why would you even want to pause it in the middle? – thuga Nov 14 '14 at 09:52
  • because my thread while sends packets uninterrupted and when I stops my ui thread for a moment errors appear because sent packets have no destination. I don't know how how to manage this! –  Nov 14 '14 at 10:44
  • Use a flag and check it before sending the packets? – thuga Nov 14 '14 at 12:47
  • Flag with what condition? –  Nov 14 '14 at 13:07
  • A bool flag that makes the thread sleep for x amount of time and upon waking up check it again. Or use a worker object that is moved to a new thread with `QObject::moveToThread`. Use a `QTimer` object instead of a while loop. This way you can just return if the flag is true and won't have to make the thread sleep. – thuga Nov 14 '14 at 14:50
  • Whats you say is correct if i know the time! But my problem is somthing diffrent! I can move my window anytime I want and I can hold it as much as I need and here comes problem and my ui thread stops and error appears! How can I manage this with timer? And if there is a way I think I should use QElapseTimer but still I dont know how to manage this! –  Nov 14 '14 at 15:58
  • What i meant by timer is use it like a while loop. What error appears? – thuga Nov 17 '14 at 07:17
  • runtime error. assert failure I think. –  Nov 17 '14 at 12:08
  • Run it in debug mode, see where it crashes. That will probably help you find out whats wrong. – thuga Nov 17 '14 at 13:44
  • I will dear tugha. Tank you for your time and answers. :) –  Nov 18 '14 at 09:54
  • @MarekR: http://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html – László Papp Dec 13 '14 at 12:31
  • @HamedBB: why are you using threads for reading at all with an async API in place?? – László Papp Dec 13 '14 at 12:31
  • @lpapp I'm an amature in qt. Please speak at my level. What can I use instead thread? I tried it before without thread and it's not working properly. I had this problem before with c# and it solves with delegate. But here I cant find a reference for this problem! Whats the correct whay to send data from thread to ui without this problem? –  Dec 13 '14 at 20:40
  • Right, can you summarize the use case without low-level thread details what you are trying to achieve? Even if you decide to go with threads, have you seen [this](https://bugreports.qt-project.org/browse/QTBUG-34946)? Have you also checked [this](https://qt-project.org/doc/qt-5-snapshot/qtserialport-creaderasync-example.html) example that I wrote back then to demonstrate the async reader use of our library? – László Papp Dec 13 '14 at 20:49
  • I explained what I'm trying to do at your answer. I think that bug report is my problem. It solved in qt-5.5.0? I can't do anything about it in qt-5.3.1? –  Dec 14 '14 at 04:22

1 Answers1

2

You are likely hitting this issue that we fixed a while ago for the 5.5 release:

Stopping streaming when window is resizing or moving

You can backport the change if you wish.

More importantly, it is relatively strange to use threading on your own when the library is designed to have an async API. I wrote a simple example back then that demonstrates the proper async use of the library for reading purposes. Here can you find it:

Command Line Reader Async Example

László Papp
  • 51,870
  • 39
  • 111
  • 135
  • 1
    thank you for your time and answers. I know you know exactly where my problem is but I think I can't do this without thread! because this code is a small part of my code. actually in here I just want to read serial port data and parse it. I'm reading data from arduino device that sends too many different packets uninterrupted and I want to update at least 20 widgets by that data and I have this ui problem too! are you sure this example solve my problem? –  Dec 14 '14 at 04:08
  • I compile your example and the output is : Usage: C:\Qt\Qt5.3.1\Tools\QtCreator\bin\build-SerialportReader-Desktop_Qt_5_3_MSVC2013_64bit-Debug\debug\SerialportReader.exe [baudrate] what I'm missing? –  Dec 14 '14 at 04:17
  • @HamedBB: please try to forget for a second about threads and assume that you may not be right. Then, try to understand how the simple example works and why and then try to integrate it into your application. If it does not work out for some reason, try to explain your use case _precisely_ from A-Z. Otherwise, it will be difficult to help. – László Papp Dec 14 '14 at 06:27
  • Ok, I will do that and let you know. –  Dec 14 '14 at 07:42
  • I can understand your code. it's simple but it reads nothing! It just print the message that I said in last comment. I don't understand what this example do! I'm sorry but as I told I'm an amateur! :| –  Dec 14 '14 at 08:10
  • Well, obviously, the example is just intentionally a simple and minimized example of how to use the async reader API through the signal/slot mechanism. It quits after a couple of seconds if there is nothing to be read, but the async reader concept is there, which I think you ought to learn and apply in your project. – László Papp Dec 14 '14 at 17:17
  • You are expert and I know you are right but as you siad it will quit if there is nothing to be read but there is! It shows nothing! –  Dec 14 '14 at 17:43
  • 1
    @HamedBB: why did you remove the selected answer status? I do not ask it for the -15 reputation, but more like the fact that the design of the library has not changed the last two weeks. o_O – László Papp Dec 29 '14 at 08:13
  • your solution didn't work in first place. It has a huge delay in reading from serial port and as I told I tried this before. I accept this because you are the only one who really spend your time to solve others problems. I don't like here anymore. I think you people don't want to help others just want to express yourselves. I will delete my account as soon as possible. –  Dec 29 '14 at 08:24
  • 1
    @HamedBB: there is no any huge delay. It is up to you how much delay you put in there. For the example, we set one constant, but you can set whatever you like, even pico seconds. – László Papp Dec 29 '14 at 08:27
  • Not important any more. Thanks :) –  Dec 29 '14 at 08:28
  • @HamedBB: not important to solve the issue just to destruct and withdraw answers without any reason? It is a very destructive way to leave the site that you kick a big into others who tried to help you before you leave. We will not go around and downvote all your questions just because you leave since it would be unhuman. In fact, I gave an upvote here: http://stackoverflow.com/questions/26314120/qt-serial-port-name-in-ubuntu – László Papp Dec 29 '14 at 08:29
  • I told you I marked this just because I admired you. But your solution didn't worked for me! What do you expect? And destructive is something else here. –  Dec 29 '14 at 08:34
  • @HamedBB: why does it not work? Have you changed the timeout from 5 seconds in the example to something lower? What did you achieve with unselecting the answer? What has changed other than generating this dicussion? – László Papp Dec 29 '14 at 08:36
  • I dont care about your up or down vote here. I like programming. But I'm an amature. I need sites like this that I can ask my questions but not in this way! New people not welcome here. Thats the fact! –  Dec 29 '14 at 08:38
  • @HamedBB: that is quite incorrect. Newcomers are welcome with good question. You got answers for your question. Anyway, goodbye! – László Papp Dec 29 '14 at 08:41
  • I did not use time out at all. I did not start this dicussion! You asked I answered. –  Dec 29 '14 at 08:42
  • You _have_ to use a timeout if you use QtSerialPort for this case; like it or not, but I am afraid that this is the answer. This would be the same answer if you came to our upstream bugtracker, too. This is not a Stack Overflow specific answer. – László Papp Dec 29 '14 at 08:46
  • Tell your friends down vote all of my question before I leave. Thats who you people are. You like it or not :) –  Dec 29 '14 at 08:48
  • I am not sure what you are talking about. If you have any issues with the timeout, point it out, or just leave then if you cannot find any issues with it. That is how this library should work. You are not obliged to use our library. You can invent your own, but even then, this will be pretty much what you get on Linux anyway. – László Papp Dec 29 '14 at 08:49