Solved Why "standard " Linux sleep(x) - as defined in uinstd.h does not work as expected ?
-
I expect the following code to output "step one" , then wait 15 seconds before outputting next steps.
It waits for 15 seconds then outputs all at once.
Any reason ?
#include <unistd.h>
ui->plainTextEdit_4->setPlainText("STEP ONE INFO NAME ");
sleep(15);
ui->plainTextEdit_4->appendPlainText("STEP two INFO NAME ");
discoveryAgent->start();
ui->plainTextEdit_4->appendPlainText("STEP three INFO NAME "); -
never use sleep() in a QObject derived class. The QObject class has its own event loop and sleep() interferes with its ability to process events. It's also an innaccurate delay mechanism because it can be woken up by a signal, and it may delay "longer" than the requested interval.
-
@AnneRanch
Because the widget is not shown as updated aftersetPlainText()
till the event loop is hit. Which doesn't happen whilesleep(15);
is executing, only afterward. Thesleep()
itself is working as documented. You must not usesleep()
, you need to use aQTimer()
(Qtimer::singleShot()
in this case). -
never use sleep() in a QObject derived class. The QObject class has its own event loop and sleep() interferes with its ability to process events. It's also an innaccurate delay mechanism because it can be woken up by a signal, and it may delay "longer" than the requested interval.
-
@Kent-Dorfman said in Why "standard " Linux sleep(x) - as defined in uinstd.h does not work as expected ?:
never use sleep() in a QObject derived class. The QObject class has its own event loop and sleep() interferes with its ability to process events. It's also an innaccurate delay mechanism because it can be woken up by a signal, and it may delay "longer" than the requested interval.
Thanks, makes perfect sense.
BUT ... the usual "but"is there a general documentation describing how this "event loop" works ?
Is it similar to "thread / process " ?
PS Accuracy in my case was irrelevant.
-
-
Here is my implementation of QTimer. It does not work as expected
delay
set first lines in plain text widget
delay
set second set of linesI get
immediately second set of linesthen 5 seconds later
two consecutive "debug delay " outputsif(1) { startHelloWave(); // 5 s delay ui->plainTextEdit_4->setPlainText("test delay "); ui->plainTextEdit_4->appendPlainText("test delay "); startHelloWave(); // 5 s delay ui->plainTextEdit_4->setPlainText("AFTER delay test delay "); ui->plainTextEdit_4->appendPlainText("test delay "); } return;
Application output
void CCC_DiscoverDevice::on_checkBox_clicked(bool checked)
5 seconds delay !
5 seconds delay !
/media/z/DEV_COPY_LABEL/Qt/QT/qtconnectivity/examples/bluetooth/build-CAT_BT-Desktop-Debug/btscanner exited with code 0QTimer code
void CCC_DiscoverDevice::startHelloWave() { timerDelay->singleShot(5 * 1000, this, SLOT(helloWave())); } void CCC_DiscoverDevice::helloWave() { qDebug() << "5 seconds delay !"; //timerDelay->singleShot(5 * 1000, this, SLOT(helloWave())); }
What did I do wrong ?
-
You're thinking in sequential programming terms, not event driven. consider the timer an asynchronous background task, not a blocking task. Use the expired() slots to do "something" when the timer expires.
Your program in Qt is ALWAYS doing something. Anything you do that blocks will interfere with that process, so you MUST trigger things based on events happening, not an expecation that an operation will take some set amount of time.
-
void CCC_DiscoverDevice::startHelloWave() { ui->plainTextEdit_4->setPlainText(QString("Hello: starting at time %1").arg(QTime::currentTime().toString("hh:mm:ss"))); timerDelay->singleShot(5 * 1000, this, &CCC_DiscoverDevice::helloWave); } void CCC_DiscoverDevice::helloWave() { ui->plainTextEdit_4->setPlainText(QString("Goodbye: ending at time %1").arg(QTime::currentTime().toString("hh:mm:ss"))); }
You must do the changing of the textedit in the slot which is called on timer expiry. That's how an event-driven system works.
-
Allow me reply with (positive) vent.
Yes, I build my first sequential application – in 1973 - coding in assembly.
I have selected Qt because I need a GUI , not because I need event driven IDE .
After trying (unsuccessfully) many Qt build-in examples I settled for QtDesigner wizard and build plain , basic “main window” . It worked as expected , even without SINGLE line code of comments. Yes, the “tooltips” are nice and very useful…
Some of the forum participants may have noticed that I have been posting few “ how does this work..” questions.
To my "defence" – the only computer book I have ever actually read from cover to cover was “K&R C programming language”. I only RTFM or ask Mrs Google about what is helping me to resolve an issue and most of the time my “problem” is in using wrong , unfamiliar terminology.
I see this discussion as THE MOST important and HELPFUL, in the series of my posts, and BEST conducted – in theory and in practice.
Important because it (finally) points out the fundamental concept of event driven software. ( Perhaps I should have pay more attention when using Windows).
Thanks
Cheers -
I am back...
Single delay works as advertised...I need ONE more advise ... how do I cascade / loop the delays ?
In another words - how start another single shot?
Obviously my code is again sequential , hence wrong.
Eventually I will need delays in a loop - sending asynchronous data...if(1)
{
//startHelloWave();
startHelloWave(); // display starting time
// return;// QTimer::singleShot(5*1000, this, SLOT(quit())); ui->plainTextEdit_4->appendPlainText("Initial test delay "); ui->plainTextEdit_4->appendPlainText("test delay "); startHelloWave(); // another delay ui->plainTextEdit_4->appendPlainText("AFTER delay test delay "); ui->plainTextEdit_4->appendPlainText("test delay "); } return;
-
Within reason, you can start as many timers as you want to, all with different timeouts, if that is your intention. Another method for period based computing is to start a singel short interval timer that reruns, and in its expire() slot count the number of times it expired and implement switch or if-else logic to execute code once it's expired the proper number of times; resetting the counter after the largest tracked interval.
-
@AnneRanch
The caller can set off multipleQTimer::singleshot()
s (it'sstatic
) with different delays in advance, calling the same or different slots:QTimer::singleShot(5 * 1000, this, &CCC_DiscoverDevice::helloWave); QTimer::singleShot(10 * 1000, this, &CCC_DiscoverDevice::helloWave); QTimer::singleShot(15 * 1000, this, &CCC_DiscoverDevice::differentWave);
Or, the slot can set off a new one, calling the same or different slot:
void CCC_DiscoverDevice::helloWave() { ui->plainTextEdit_4->setPlainText(...); QTimer::singleShot(15 * 1000, this, &CCC_DiscoverDevice::differentWave); // if you call the same slot like next line, it will keep repeating, as this line will be hit again next time // you'll need some `if (...)` if you no longer wish to keep repeating QTimer::singleShot(15 * 1000, this, &CCC_DiscoverDevice::helloWave); }
Or, don't use
singleShot()
.QTimer
is a repeating timer:timerDelay->callOnTimeout(&CCC_DiscoverDevice::helloWave); timer->start(5000);
calls the same slot every 5 seconds. Call
timer->stop()
to switch it off.