GUI app frozen while process and generate a file - c++

I have a QT GUI application in c++ that aims to process and generates binary files.
The App works fine but it looks like it's frozen when it enters the while loop of processing and writing in the file.
I solve this by coping qApp->processEvents(); into the while loop. but the problem is that it takes much more time for generating a file:
without qApp->processEvents(); in the loop => it takes 4second
with qApp->processEvents(); in the loop => it takes 50 second for exact the same file
for (unsigned long int k=0; k<DATASIZE ; k++){
qApp->processEvents();
/* Some process*/
DataToFile.push_back(Process_Function(DATA));
}
/*Generating file*/
myFile.write((char *)&DataToFile[0], DataToFile.size()*sizeof (float));
DATA SIZE around a couple of millions
Process_Function: take specific data, calculate the value and return it back.
Questions:
1- Is there a way to process the data, generate files without being frozen and without the huge delay of the qApp->processEvents();
2- Is it possible to run qApp->processEvents(); in another thread? / OR is there another way to do it?

First, create an object that encapsulates your work:
class Generator : public QObject {
Q_OBJECT
signals:
void progress(float);
void done();
slots:
void doWork() {
QVector<float> DataToFile;
for (unsigned long int k=0; k<DATASIZE ; k++){
/* Some process*/
DataToFile.push_back(Process_Function(DATA));
if (k % 100 == 0) { // Inform the UI thread every 100 datapoints
emit progress(k/DATASIZE);
}
}
myFile.write((char *)&DataToFile[0], DataToFile.size()*sizeof (float));
emit done();
}
};
Then create a new thread and have the object do its work there:
QThread *t = new QThread(this);
Generator *g = new Generator;
g->moveToThread(t);
QObject::connect(t, &QThread::started, g, &Generator::doWork);
QObject::connect(g, &Generator::done, t, &QThread::quit);
QObject::connect(t, &QThread::finished, g, &QObject::deleteLater);
QObject::connect(t, &QThread::finished, t, &QThread::deleteLater);
t->start();
The first two connect statements tie the lifetime of the generator to that of the thread, the last two clean up everything once the thread exits.
And you can of course connect to the Generator::progress signal to monitor the generation progress.

Related

How can I connect QtcpSockets to about 100 servers without a UI hang?

How can I connect QtcpSockets to about 100 servers without a UI hang?
When I create 100 QTcpSockets to connect to each server and call the connectToHost() function, the QDialog stuck. Is there a way to run the connectToHost() part as a background job?
As a result, all connections are made, but while trying to connect (call connectToHost() the UI is in 'No Response' state.
// onConnectToICPMC is the slot function connected to the dialog button pressed signal
void WidgetUploadFile::onConnectToICPMC()
{
// m_tcpClients is a QVector containing a custm QObject Class that manages QTcpSocket
for(int i = 0; i < m_tcpClients.size(); ++i)
{
if(m_tcpClients.at(i)->state() != QAbstractSocket::ConnectedState)
{
m_tcpClients.at(i)->connectToServer(); // Call the connectToHost() function of QTcpSocket.
}
emit sendConnProgBarUpdate(i+1);
emit sendCurrentSockLog(m_tcpClients.at(i)->ipAddress(), m_tcpClients.at(i)->state());
}
}
A dialog that hangs while each QTcpSocket connects to the server.:
After all QTcpSockets try to connect to the server:
Time-consuming tasks should not be run on the main thread. In that case there are 2 strategies:
Use of threads.
Divide into subtasks and execute in parts every T seconds.
In this case I think the second option is the best using QTimeLine.
*.h
private:
void handleFrameChanged(int i);
QTimeLine timeLine;
*.cpp
{
// constructor
timeLine.setRange(0, m_tcpClients.size()-1);
connect(&timeLine, &QTimeLine::frameChanged, this, &WidgetUploadFile::handleFrameChanged);
}
void WidgetUploadFile::onConnectToICPMC()
{
timeLine.start();
}
void WidgetUploadFile::handleFrameChanged(int i){
auto client = m_tcpClients.at(i);
if(client->state() != QAbstractSocket::ConnectedState){
client->connectToServer();
}
emit sendConnProgBarUpdate(i + 1);
emit sendConnProgBarUpdate(client->ipAddress(), client->state());
}

Passing classes to worker in QThread

I'm developing an application which parses a list of binary files and saves the results into a database. The processing of the files takes a rather long time. Therefore I'm showing the user a progress bar and a list of processed files. When a file is successfully processed, I want to update the processbar. If the user aborts the processing (i.e. clicks on the window's 'x' -> &ParseAssistant::rejected), I need to kill the thread and delete the allocated objects (i.e. PluginWorker* and QThread*).
/* mainwindow.cpp */
ParseAssistant parseWindow(files.size());
QThread* thread = new QThread();
PluginWorker* worker = new PluginWorker(pluginConnector, pluginProcessor, files);
worker->moveToThread(thread);
// Update GUI (progressbar + filelist)
connect(worker, &PluginWorker::updateProgress, &parseWindow, &ParseAssistant::updateProgress);
connect(thread, SIGNAL (started()), worker, SLOT (process()));
connect(worker, SIGNAL (finished()), thread, SLOT (quit()));
connect(thread, SIGNAL (finished()), thread, SLOT (deleteLater()));
connect(worker, SIGNAL (finished()), worker, SLOT (deleteLater()));
// Stop PluginWorker on 'x'-click
connect(&parseWindow, &ParseAssistant::rejected, worker, &PluginWorker::stop);
connect(worker, &PluginWorker::finished, &parseWindow, &ParseAssistant::parsingFinished);
thread->start();
parseWindow.exec();
First, I'm creating a QDialog (ParseAssistant) which contains the progressbar and the list of processed files. Afterwards I create a Worker-Thread-pair and bind them as described in 'How To Really, Truly Use QThreads'. The 'pluginConnector' has access to the plugin an parses the files; the pluginProcessor writes the results to a database.
/* pluginworker.cpp */
PluginWorker::PluginWorker(PluginConnector& pc, PluginProcessor& processor, QStringList list)
{
connect(this, SIGNAL(parseNext(int)), this, SLOT(process(int)));
}
// Called on 'x'-press
void PluginWorker::stop()
{
isStopped = true;
}
void PluginWorker::process(int idx)
{
if (isStopped) {
emit finished();
return;
}
if (0 <= idx && idx < files.length()) {
/*
* Parse file using PluginConnector and
* use result with PluginProcessor
*/
emit updateProgress(idx+1, error, source);
emit parseNext(idx+1);
} else {
emit finished();
}
}
I use signals/slots to call parseNext, because this allows Qt to call stop() (when &ParseAssistant::rejected signal is received). An alternative would be to iterate over the files and call QCoreApplication::processEvents to process signals.
This construct mostly works, but crashes when I abort the process using the 'x'. I can't track down exactly what crashes the application, but I'm fairly certain that my approach is flawed, because the 'worker' and the 'pluginConnector/pluginProcessor' live in different threads, but I don't know how to correctly use this.

qt serial port memory leak

I use the following code to talk to a USB-serial port device:
#include "masterthread.h"
#include <QtSerialPort/QSerialPort>
#include <QTime>
#include "Windows.h"
#include "Psapi.h"
#include <QDebug>
QT_USE_NAMESPACE
MasterThread::MasterThread(QObject *parent)
: QThread(parent), waitTimeout(0), quit(false)
{
}
MasterThread::~MasterThread()
{
mutex.lock();
quit = true;
cond.wakeOne();
mutex.unlock();
wait();
}
void MasterThread::run()
{
bool currentPortNameChanged = false;
QSerialPort serial;
serial.setPortName("COM3");
serial.setBaudRate(57600);
serial.setStopBits(static_cast<QSerialPort::StopBits>(1));
serial.setDataBits(static_cast<QSerialPort::DataBits>(8));
serial.setParity(static_cast<QSerialPort::Parity>(0));
serial.open(QIODevice::ReadWrite);
//Tell the serial port connected device to start talking
//--------------------------------------
const char init[] = { 0x0d, 0x0d, 0x0d };
serial.write(init, sizeof(init));
const char* cmd = "mavlink stop\n";
serial.write(cmd, strlen(cmd));
serial.write(init, 2);
cmd = "uorb start";
serial.write(cmd, strlen(cmd));
serial.write(init, 2);
cmd = "sh /etc/init.d/rc.usb\n";
serial.write(cmd, strlen(cmd));
serial.write(init, 4);
serial.waitForBytesWritten(100);
int i = 0;
int j = 0;
forever
{
//Write test data out
//-----------------------------
QByteArray test(2000, 't');
serial.write(test);
bool check = serial.waitForBytesWritten(100);
if (!check)
{
qDebug() << "FAIL: " << j++;
}
if (serial.waitForReadyRead(20))
{
QByteArray responseData = serial.readAll();
while (serial.waitForReadyRead(10))
responseData += serial.readAll();
QString response(responseData);
qDebug() << response;
}
QThread::msleep(20);
//Print memory usage
//---------------------------------------------------
if (i++ % 10 == 0)
{
PROCESS_MEMORY_COUNTERS memcount;
if (!GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) return;
qDebug()<<"----------------------------" << memcount.WorkingSetSize / 1024 << "KB memory used";
}
} // end foever
qDebug() << "Exiting forever loop";
}
with a simple main.cpp as:
#include <QApplication>
#include "masterthread.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MasterThread thread;
thread.start();
return app.exec();
}
But the memory usage keeps increasing, like 5~10MB per hour as if there are some leakage.
The device is suppose to be connected for days and weeks...
What am I doing wrong here? I am on Qt5.6 windows7 debug
Many Qt Components have an implicit dependency on its event loop.
While you are starting the main threads event loop with the call to app.exec(); you are not handling events generated by the QObjects created in the QThread MasterThread thread;. The details and nuances of Event handling in Qt are very well described on this page: https://wiki.qt.io/Threads_Events_QObjects#Threads_and_QObjects
But the solution boils down to: if you want to be able to process queued up Qt events in a thread where you are processing some long-running task you should call QCoreApplication::processEvents(); from time to time. This will prevent Qt events from endlessly queueing up.
EDITED after looking on the code Qt 5.7,5.6,5.5 and reading docs.
As an answer is already accepted, I would just add some thoughts here as it's too long for comments.
Keep things short - an answer you accepted is wrong..
There are two sides of the story. And as SO answers often taken 'as it is as long as they work' I'd like to explain myself...
If you look on a code provided - there is nothing wrong with it. All objects are properly stack allocated and should be destroyed automatically.
Point is that QtSerial uses deleteLater() and then a question - how to delete those allocations properly.
If any module/object/code uses deleteLater() it requires an event loop, if deleteLater() called on a thread without event loop, object will be deleted after thread is terminated. As long as there is no event loop running for code above, processEvents will no work.. actually processEvents() is not something which is used for this, because a whole idea to return from the context which is called deleteLater() and have a next run, and that's checked in the Qt Source Code, so calling processEvent() straight after without incrementing loop count will do nothing at all, that's why answer you accepted is totally wrong.
Conclusion:
If any object requires event loop running it should be EXPLICITELY stated in the documentation as there is nothing wrong in using QIODevice in sync mode outside event loop.
So at my opinion,point is - its a bug in the QT Serial itself which I suggest you report.
In general it's really wrong practice for Qt to run never-ending loops..
It's much much better and cleaner to use QObject Worker tactic which is pushed to the thread, have proper even loop running etc.
For small 'threaded' tasks it's much better to use QtConcurrent.
Proper Workaround:
you will have a thread with properly running event loop and a timer firing at 20ms to do your things
// main thread:
class Worker: public QObject {
public:
Worker();
public slots:
onInit() {
// initialize everything
startTimer(20);
}
protected:
void timerEvent(..) {
// do your things every 20ms
}
}
...
QThread * pWorkerThread = new QThread();
pWorkerThread->setObjectName(QString("Serial"));
Worker * pWorker = new Worker();
Worker->setObjectName(QString("Common Storage Impl"));
Worker->moveToThread(WorkerThread);
connect(pWorkerThread, SIGNAL(started()), pWorker, SLOT(onInit()));
connect(pWorkerThread, SIGNAL(finished()), pWorker, SLOT(deleteLater()));
connect(pWorkerThread, SIGNAL(finished()), pWorkerThread, SLOT(deleteLater()));
pWorkerThread->start();
...

Qt change picture on timer

I'm trying to change the image on QLabel in Qt.
At first, I did the basic set image as follows:
void MainWindow::setMainDisplayNew(QString imageName){
QPixmap pix7 = imageName;
QPixmap pix8 = pix7.scaled(QSize(720,480), Qt::KeepAspectRatio);
ui->mainDisplay->setStyleSheet(imageName);
ui->mainDisplay->setPixmap(pix8);
}
Now I want to change this so I can pass 2 arrays. List of images and duration they should appear for and I want the display to show them for the indicated duration.
void MainWindow::setMainDisplay(QString imageName[], int size)
{
for(unsigned int i=0; i<size; i++)
{
QTimer * timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=](){
setMainDisplayNew(imageName[i]);
timer->deleteLater(); // ensure we cleanup the timer
});
timer->start(3000);
}
}
EDIT
With the help of the responses, I reached the above code. I am sending the 3 images. It is display the final image after 3 seconds and stays as is... Any help?
while(true){
This is your problem. Qt is an event-driven framework. The while(true) prevents events from being processed. Such events include the timeout from the QTimer and updating of the GUI. You need to allow the function to exit.
In addition, you're not cleaning up your timers, so you're leaking memory every time you enter the function (although that's currently only once!). You can clean up with a call to deleteLater.
Using C++ 11, it would be something like this: -
for(int i=0; i<mySize; i++)
{
QTimer * timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=](){
setMainDisplayNew(imageName[i]);
timer->deleteLater(); // ensure we cleanup the timer
});
timer->start(duration[i]);
}

How to make blocking tcp socket with Qt?

I work with QTcpSocket. I need any write/read calls to the socket to be synchronous (blocking).
I know there is waitForReadyRead() and waitForBytesWritten(), but those two methods are marked in Qt documentation as they can fail randomly under Windows. I cannot affort this.
The blocking read is the most important (as reading comes always after writting a command to the other peer, so I know that if data reaches the other peer, it will answer).
I have tried 2 approaches.
First:
QByteArray readBytes(qint64 count)
{
int sleepIterations = 0;
QByteArray resultBytes;
while (resultBytes.size() < count && sleepIterations < 100)
{
if (socket->bytesAvailable() == 0)
{
sleepIterations++;
QThread::msleep(100);
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
continue;
}
resultBytes += socket->read(qMin(count, socket->bytesAvailable()));
}
return resultBytes;
}
This should wait for bytes to be available for reading on the socket, processing the event loop in the mean time, so the socket is doing it's necessary internal stuff.
Unfortunately - for unknown to me reason - the bytesAvailable() sometimes returns correct number of bytes, but sometimes it never returns anything greater than 0.
I know in fact that there was data to be read, because it used to work with the second approach (but it has it's own problems).
Second:
I have a kind of signal "blocker", which blocks current context and processes event loop, until certain signal is emitted. This is the "blocker":
SignalWait.h:
class SignalWait : public QObject
{
Q_OBJECT
public:
SignalWait(QObject *object, const char *signal);
bool wait(int msTimeout);
private:
bool called = false;
private slots:
void handleSignal();
};
SignalWait.cpp:
SignalWait::SignalWait(QObject* object, const char* signal) :
QObject()
{
connect(object, signal, this, SLOT(handleSignal()));
}
bool SignalWait::wait(int msTimeout)
{
QTime timer(0, 0, 0, msTimeout);
timer.start();
while (!called && timer.elapsed() < msTimeout)
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
return called;
}
void SignalWait::handleSignal()
{
called = true;
}
and then I used it like this:
SignalWait signalWait(socket, SIGNAL(readyRead()));
// ...
// socket->write(...);
// ...
if (!signalWait.wait(30000))
{
// error
return;
}
bytes = socket->read(size);
This approach seems to be working better, but it also fails from time to time. I don't know why. It's like the readyRead() signal was never emitted and the SignalWait keeps waiting, until it times out.
I'm out of ideas. What is the proper way to deal with it?
I would suggest to use the asynchronous approach but if you really want to go with the synchronous way, then a better way is to use a local event loop:
QTimer timer;
timer.setSingleShot(true);
QEventLoop loop;
loop.connect(socket, SIGNAL(readyRead()), SLOT(quit()));
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
while (resultBytes.size() < count)
{
timer.start(msTimeout);
loop.exec();
if(timer.isActive())
resultBytes += socket->read(qMin(count, socket->bytesAvailable()));
else
break;
}
Here it waits until count bytes are read or the the timeout reaches.