Sean Gao
Sean Gao

Reputation: 1

A stranger problem about QTimer::singleShot

I wrote a function calling QTimer::singleShot to make sure it should not be timeout. But I got a stranger result.

int Test(int x)
{
    QEventLoop loop;

    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, [&](){
        loop.exit(x);
    });
    timer.start(7000);

    QTimer::singleShot(10000, std::bind(&QEventLoop::exit, &loop, 3));

    return loop.exec();
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);


    qDebug() << Test(1) << endl;
    qDebug() << Test(2) << endl;

    return a.exec();
}

I expect the output to be 1 2 but the actual output is 1 3

Upvotes: 0

Views: 158

Answers (1)

G.M.
G.M.

Reputation: 12879

Looks like undefined behaviour. With regard to why you might be seeing the symptoms as described, consider your implementation of Test...

int Test(int x)
{
    QEventLoop loop;

    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, [&](){
        loop.exit(x);
    });
    timer.start(7000);

    QTimer::singleShot(10000, std::bind(&QEventLoop::exit, &loop, 3));

    return loop.exec();
}

You construct a local QEventLoop. You then set up two timer callbacks (after 7s and 10s) that both exit the local event loop. The first timeout will exit the loop causing Test to finish and return. But there is still a timeout pending which will also try to exit the now invalid QEventLoop. When you call Test again as Test(2) there is a strong probability that the new QEventLoop will be constructed at the same address as for the previous call to Test. The net result being that the QEventLoop address used by the still pending timeout becomes ``valid''. Hence, the two values you see are actually from the two timeout events from the call to Test(1).

As I said at the start though -- undefined behaviour.

Upvotes: 1

Related Questions