QEventLoop and qWait interaction



  • I'm using a series of QEventLoops in order to concurrently wait for specific signals with specific parameters in different parts of my code without blocking the rest of the application (no gui). This is required as these signals rely the information on whether certain operations did succeed or not.

    This code looks like this:

    if ( !expectMySignals(lambdaWithTriggeringAction, signals...)
    {
        zError("Error while receiving events, aborting...");
        return end();
    }
    
    // continue...
    

    With the expectMySignals function looking like this:

    bool expectMySignals(...) 
    {
        QEventLoop loop;
        QTimer timer;
        // This keeps track of all incoming signals and emits()
        // when they all arrived.
        SignalVerifier verifier;
    
        if (!/* Bind verifier to all required signals */)
            return false;
    
        if (!QObject::connect(&verifier, SIGNAL(verified()), &loop, SLOT(quit())))
            return false;
    
        if (!QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())))
            return false;
    
        runLambdaWithTriggeringAction();
    
        // IMPORTANT:
        // We wait AT MOST 5 seconds for the signals, otherwise we abort
        timer.start(5000);
    
        loop.exec();
        return verifier.isVerified();
    }
    

    I'm using this solution in order to keep the code as streamlined as possible, without the need to split execution into numerous multiple functions called when all signals arrive.

    Everything seems to work correctly, but when writing tests for this code I have noticed that, if concurrent qWaits to this code exist and the signals do not arrive, the code after a qWait does not get executed until the timer within expectMySignals does not expire, no matter the amount of time specified within qWait. For example:

    QSignalSpy tester(/* some binding to test */);
    
    doAction();
    
    // We want to give a bit of time to the code to do its work.
    // Then it should wait for signals incoming.
    
    QTest::qWait(500);  /* <-- This blocks for some reason until
                               expectMySignals fails, no matter 
                               the number inside (be 500, 50, 1..) */
    
    triggerExpectedSignals();
    QTest::qWait(500);
    
    // We test that the code did its job.
    QVERIFY(tester.count() == 1);
    

    Why does this happen?


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Your base design sounds a bit convoluted. Why not just trigger a check when you receive these signals and only start the rest once they all have been received ? Something maybe like a state machine



  • @SGaist Hi, thanks for the welcome. I actually did just do that, even though I like this style less (I had to do a switch with all the state machine states, and after verifying the signals I would call the same function with a different state instead of a simple if/else).

    I was actually just curious on how this worked in order to understand better how Qt works under the hood =)


  • Lifetime Qt Champion

    You can find the implementation in qtestsystem.h

    It basically trigger event processing and sleeps a short time.

    Can you show a picture of how your system should work ?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.