Simple network timeout in Qt(c++) - c++

I'm writing a simple network file transfer application in Qt, and I'm struggling to implement a timeout.
Basically, what I want is the following,
while(!AcknowledgeReceived)
{
if(timeout)
{
break;
}
}
Currently, timeout is changed by a Qtimer, but once the loop starts execution, it never leaves. (The Slot QTimer emits to doesn't get executed.)
I gather that this has something to do with threads, but I'm way to new at this to implement it correctly.
So my question to you is, how do I go about ensuring that the method flipping timeout is executed, or how do I get the same results with another method?

When you're looping like that, the Qt main event loop will not run, as it's in the call to your function.
You either need to redesign your application to only use slots and signals, so you don't need the loop. Or you have to process the Qt event yourself.

For example
QNetworkAccessManager netman;
QNetworkRequest request{url};
QNetworkReply* reply = netman.post(request, data);
while (!reply->isFinished())
{
QThread::msleep(1);
qApp->processEvents();
}

Related

How to avoid freezing the user interface in a loop (minimal example) [duplicate]

My first naive at updating my progress bar was to include the following lines in my loop which is doing the processing, making something like this:
while(data.hasMoreItems())
{
doSomeProcessing(data.nextItem())
//Added these lines but they don't do anything
ui->progressBar->setValue(numberProcessed++);
ui->progressBar->repaint();
}
I thought adding the repaint() would make the execution pause while it updated the GUI, but apparently it's not that simple. After looking at the questions:
QProgressBar Error
Progress bar is not showing progress
it looks like I'm going to have to put the data processing in a different thread and then connect a signal from the data processing thread to the GUI thread to update the progressbar. I'm rather inexperienced with GUIs and threads and I was wondering if anyone could just point me in the right direction, ie what Qt classes should I be looking at using for this. I'd guess I need a QThread object but I've been looking through the QProgressBar documentation but it doesn't bring up the topic of threading.
As #rjh and #Georg have pointed out, there are essentially two different options:
Force processing of events using QApplication::processEvents(), OR
Create a thread that emits signals that can be used to update the progress bar
If you're doing any non-trivial processing, I'd recommend moving the processing to a thread.
The most important thing to know about threads is that except for the main GUI thread (which you don't start nor create), you can never update the GUI directly from within a thread.
The last parameter of QObject::connect() is a Qt::ConnectionType enum that by default takes into consideration whether threads are involved.
Thus, you should be able to create a simple subclass of QThread that does the processing:
class DataProcessingThread : public QThread
{
public:
void run();
signals:
void percentageComplete(int);
};
void MyThread::run()
{
while(data.hasMoreItems())
{
doSomeProcessing(data.nextItem())
emit percentageCompleted(computePercentageCompleted());
}
}
And then somewhere in your GUI code:
DataProcessingThread dataProcessor(/*data*/);
connect(dataProcessor, SIGNAL(percentageCompleted(int)), progressBar, SLOT(setValue(int));
dataProcessor.start();
You need to call QApplication::processEvents() periodically inside your processing loop to let it handle UI events.
As Georg says, Qt is a single-threaded co-operative multitasking environment. You get full control of your process until you relinquish it voluntarily with processEvents() - until you do that, Qt can't update the UI elements, handle async HTTP requests, handle input, or pretty much anything else. It's up to you to make sure that stuff gets a timeslice while you're in a long processing loop.
You can create a sub-class of QThread that emits a signal progressChanged, which you connect to the QProgressBar.
connect() makes the connections auto connections per default. That means that the signal-slot-mechanism already takes care of the threading issues for you, so you don't need to worry about that.

What does QTimer::singleShot(0, object SLOT(obj_slot())) do?

I'm beginner learning Qt, and trying to understand a Qt provided example for download operation. In downloadmanager.cpp, a member function is the following:
void DownloadManager::append(const QUrl &url)
{
if (downloadQueue.isEmpty())
QTimer::singleShot(0, this, SLOT(startNextDownload()));
downloadQueue.enqueue(url);
++totalCount;
}
I'm confused to why, if downloadQueue is empty, it will need to activate the startNextDownload() before adding the url. (note that: startNextDownload() ends the program if the downloadQueue is empty)
I'm unsure why: QTimer::signleShot(x, y, z) has been used at all. As I understand it to be, a timer that activates the slot with delay of 0 millisecond.
I could not figure out from looking at Qt Assistant whether singleShot is a one time setup for repeated activation to the slot at given millisecond interval or whether it is one time
Clarification:
I'm a beginner and in examples like:
statement1;
statement2;
I'm used to seeing statement1 running and finishing before moving on to working on statement2. But trying to learn Qt and reading the given example, I see the SLOT(startNextDownload()) being activated after downloadQueue.enqueue(url); has taken place. I am trying to understand why does this work.
This queues a callback in the message queue.
The timer immediately elapses, and a message is posted to the message queue. When the process reaches the main loop for the next time, the startNextDownload() function is called. By this time, the URL is in the queue.
The startNextDownload() function is called from the dispatch context, where it is safe to change window contents. This way, the DownloadManager class can be used from a multithreaded application, where the thread starting the download might be running concurrently with the handler for a Paint event. By invoking it from the same thread that would handle Paint events you can be sure that no such event is being processed, and you can update widgets safely.
If a widget needs to be repainted afterwards, it then asks to be repainted, and the OS will send a Paint event if the widget is currently visible.
Answer to current question title
Every call to QTimer::singleShot(...) is executed on the event loop of the thread where it is invoked **. If invoked from the main thread, it'll be the event loop started with app.exec().
According to the Qt-Network-Manager-Example, this function is called after the network-manager is filled with the URL's so the single-shot will be processed after the queue has been completely filled. Poorly the qt documentation isn't that clear about this topic yet, so for more information about event processing etc please look here.
Answer for old question title
Before I start, the timer is for having the download in an extra thread. So the GUI keeps responsive.
The complete downloadNext() method is recursive. It will be only called once and called till the queue is empty.
See this:
void DownloadManager::append(const QStringList &urlList)
{
foreach (QString url, urlList)
append(QUrl::fromEncoded(url.toLocal8Bit())); //Call for only one URL
...
}
void DownloadManager::append(const QUrl &url)
{
if (downloadQueue.isEmpty())
//I'm only called if the queue is empty! And I will be called after the next line. Not instantly!
QTimer::singleShot(0, this, SLOT(startNextDownload()));
downloadQueue.enqueue(url);
++totalCount;
}
After the queue is empty each method returns and at least the message that the download is done will be printed.
So why does this work?
Please see first chapter below.
you can understand things about Class QTimer before you end up with a solution as you desire, please have a look here for your understanding

Asynchronous function calls in Qt

I'm pretty new to Qt and programming and are facing a problem I can't find a solution for.
I want to read some information from an online XML file and send it to my main program.
To do so, I created a class XMLParser and added the following to the constructor:
XMLParser::XMLParser(QString searchstring)
{
QNetworkAccessManager *manager2 = new QNetworkAccessManager(this);
reply = manager2->get(QNetworkRequest(QUrl("http://www.boardgamegeek.com/xmlapi/search?search="+searchstring)));
XMLParser::connect(reply, SIGNAL(finished()),
this, SLOT(fileIsReady()) );
}
and fileIsReady fills a QMap and stores it as a private class member.
In my second class, I call
XMLParser *xmlpars = new XMLParser(input_gamename->text());
QMap<QString, int> searchResults = xmlpars->getSearchList();
and getSearchList is a simple getter function.
The problem is, that getSearchList is executed before fileIsReady finished reading the XML file and returns an empty map.
From what I understand, the constructor should not be finished until fileIsReady() finished its work. And thus, getSearchList() shouldn't be called early.
My two questions:
Why does my programm progresses while the function didn't finish reading.
How can I make the second call "getSearchList" wait?
Thanks a lot in advance!
First, you need to understand the fundamental concept of signals and slots.
After you make a connection, the slot will get called every time the signal is emitted.
The connect() functions returns after connecting the signal to the slot. It doesn't wait for the signal to be emitted.
In your XMLParser constructor, your connect() function registers this: "When the finished() signal is emitted, run the fileIsReady() function".
Now, to answer your questions.
Why does my programm progresses while the function didn't finish reading.
Because in your constructor code, you asked the constructor to finish after you connect the signal to the slot. You did not ask it to wait for the download to finish.
And then, you call getSearchList() without waiting for the finished() signal. So, getSearchList() gets called before fileIsReady().
How can I make the second call "getSearchList" wait?
Like MrEricSir said, you shouldn't ask it to wait! (Think about it: What happens if you lose internet connection and can't finish downloading the file? The answer is, your program will freeze because it will wait forever. That's bad.)
Don't call getSearchList() immediately after constructing XMLParser. Instead, make XMLParser emit a "finishedParsing()" signal when it finishes parsing the XML file. Then, make another signal-slot connection: Connect the finishedParsing() signal to a slot that calls getSearchList().
So, I found a solution using QEventLoop. But as far as I read, this isn't recommendend.
Are there any other solutions? And why is using QEventLoop bad habit (That's what I read from other answers here StackOverflow).
XMLParser::XMLParser(QString searchstring)
{
QNetworkAccessManager *manager2 = new QNetworkAccessManager(this);
reply = manager2->get(QNetworkRequest(QUrl("http://www.boardgamegeek.com/xmlapi/search?search="+searchstring)));
QEventLoop loop;
XMLParser::connect(reply, SIGNAL(finished()),
this, SLOT(fileIsReady()) );
XMLParser::connect(this, SIGNAL(finishedReading()),
&loop, SLOT(quit()));
loop.exec();
}
How can I make the second call getSearchList wait?
You don't! Instead, just move any code that expect the XML file to be downloaded into the fileIsReady() slot that you've already defined. That way your program won't lock up while it's waiting for the download to complete (which is the entire point of asynchronous programming.)

QT : How to determine if the event processor is busy

In my current Qt application I am attempting to shut it down using
QCoreApplication::quit();
Now it takes more than a minute for the application to shutdown. I believe this is because the event processor of the main form is busy. My question is : Is there a way for me to determine what the cause of this might be. Here are somethings that I suspect
1-Queued Connections.
I have a lot of queued connections. Maybe some of those connections dont get processed
2-Event Loop.
May be the event loop is busy doing something that I dont know (expect)
Any suggestions on what I could do to check why the app takes so long to close ?
Update:
I tried QCoreApplication::hasPendingEvents() and that returns true
There's no such thing as queued connections that are "not" processed, or event loop being "busy". An event loop is, essentially, this (in C++ pseudocode):
forever {
while (! nativeEventQueue.isEmpty()) {
QueueEntry entry = nativeEventQueue.take_first().convert();
QCoreApplication::sendEvent(entry.object, entry.event);
delete entry.event;
}
while (! eventQueue.isEmpty()) {
QueueEntry entry(eventQueue.take_first());
QCoreApplication::sendEvent(entry.object, entry.event);
delete entry.event;
}
waitFor(eventQueue, nativeEvents);
}
All of the event processing is done by sending some QEvent to a QObject. That's all that the event loop does. Some events result in the signals being emitted. It's not the event loop that is busy, it's the code that runs in the QObject::event and overridden implementations! This code blocks the event loop, since when it runs, the event loop's code is in the same thread and is on the call stack - it can't run.
Your code in slots connected to signals in Qt widgets and other objects is really executed while QCoreApplication::sendEvent and QCoreApplication::notify is on the call stack, with the event loop (a QAbstractEventDispatcher) somewhere deeper in the call stack, and finally a QEventLoop under it.
If your code executes at a pace that is slower than the events are added to the queue, you will have problems.
This trivial example demonstrates such code. In real programs it'll be of course "obfuscated", but the problem often reduces to:
void Class::customEvent(QEvent * ev) {
...
QCoreApplication::postEvent(this, new EventFoo(...));
...
QCoreApplication::postEvent(this, new EventFoo(...));
...
}
The explicit event posting can be expressed very differently. For example, it could be you sending a signal to yourself:
void Class::mySlot() {
...
emit signal1();
...
emit signal2();
}
If both signal1 and signal2 are connected to mySlot through a queued connection, your application will run out of memory, as the event queue will only grow, never shrink. It may still appear responsive.

Qt How to update main windows from running thread , the right way

I have simple application that in the main view I have QListview . my flow going like this I need to know if it right
1.App starts and start single thread , also see signal/slot connect between the thread object and the main app
2.Thread gets data from remote server as xml format its and sets the data into object container (class that represent the data )
3.when the data is ready in the object it trigger SIGNAL back to the main app (the signal/slot from section 1)
4.The SIGNAL invoking update function that sets the formatted data into the QListView via its model (QAbstractListModel)
The problem is when stage 4 is happening I see some frize in the application for 2-3 seconds that makes me wonder what is wrong here .
UPDATE:
after profiling the app with sleepy
it looks like the delay in the app im not sure but is shows in the Exclusive column
very high number 322.35s.
in my Thread that calls the http request inside the run method i have this code that couse the thread to pause.
void RequestThread::run()
{
m_RequestThreadTimer = new QTimer();
connect(m_RequestThreadTimer, SIGNAL(timeout()),
this,SLOT(fire(),Qt::DirectConnection));
QVariant val(GetValFromConfig());
int interval = val.toInt();
m_RequestThreadTimer->setInterval(interval);
m_RequestThreadTimer->start();
QThread::exec();
}
but now is the question how to improve it ?
I suspect that since you create the timer in the QThread::run() method the slot the timer connects to is being called in the context of the main thread.
You don't need to subclass QThread to run code in its own thread.
Just subclass a QObject, add the functionality you want, create a QThread instance, start it and use the QObject::moveToThread() method to set the QObject's thread affinity to the new thread.
worker = new WorkerClass;
connect(worker,SIGNAL(response(QString)),this,SLOT(response(QString)));
QThread *t = new QThread;
t->start();
worker->moveToThread(t);
//Start it either like this or by emitting a signal connected to the startWorking slot
QMetaObject::invokeMethod(worker,"startWorking",Qt::QueuedConnection);
I suggest you to use the QEventloop in the case of the thread.
Start the event loop in the main
//start the function to get data from remote server
GetData::getInstance()->StratReading();
QEventLoop loop; //loop to continue the reading.
loop.connect(GetData::getInstance(),SIGNAL(ReadingFinished()),SLOT(quit()));
loop.exec();
GetData::StratReading()
{
//sets the data into object container
//the data is ready in the object it trigger SIGNAL to main function to update to Ui
emit ReadingFinished(); //this will quit the loop
}