Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 after setPlainText() till the event loop is hit. Which doesn't happen while sleep(15); is executing, only afterward. The sleep() itself is working as documented. You must not use sleep(), you need to use a QTimer() (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.


  • Lifetime Qt Champion



  • 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 lines

    I get
    immediately second set of lines

    then 5 seconds later
    two consecutive "debug delay " outputs

      if(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 0

    QTimer 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.



  • @AnneRanch

    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 multiple QTimer::singleshot()s (it's static) 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.


Log in to reply