开发者

Why won't my nested QEventLoop deliver all the events for my QThread?

I'm having a problem with QEventLoop. I want to create a "TimeBoundExerciser" for my unit test so that my SUT, which blocks on a QEventLoop, won't block the rest of the test cases. Specifically, my test case is to make sure the SUT terminates after a timeout.

The TimeBoundExerciser basically spawns a thread, executes the SUT on that thread, waits for the thread to terminate, and if it doesn't terminate after a specific amount of time, invokes the quit() method on the thread through QMetaObject::invokeMethod() and a QueuedConnection. I would expect that executing quit() will cause my nested QEventLoop to exit, terminating my thread. However, what I've found is that the quit() method is never invoked, and the thread never terminates. The code for my TimeBoundExerciser is below:

class IExerciseTheSystem
{
    void operator()() = 0;
};

class TimeBoundExerciser : private QThread
{
Q_OBJECT
public:
    enum CompletionType
    {
        TERMINATED,
        FORCE_QUIT,
        QUIT
    };
    TimeBoundExerciser(const IExerciseTheSystem& exerciser);
    CompletionType exercise(unsigned long timeoutMillis);   
protected:
    void run();

protected slots:
    void exerciseTheSystem();
private:
    const IExerciseTheSystem& exerciser;
};

TimeBoundExerciser::TimeBoundExerciser(const IExerciseTheSystem& exerciser) : exerciser(exerciser)
{

}

TimeBoundExerciser::CompletionType TimeBoundExercise开发者_如何转开发r::exercise(unsigned long timeoutMillis)
{
    start();
    while (!isRunning()) 
    {
        msleep(10);
    }

    moveToThread(this);

    wait(timeoutMillis);
    if (!isFinished()) 
    {
        bool quitResult;
        QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection, Q_RETURN_ARG(bool, quitResult));
        wait();
        return FORCE_QUIT;
    }

    return QUIT;
}

void TimeBoundExerciser::run()
{
    setTerminationEnabled(true);
    QMetaObject::invokeMethod(this, "exerciseTheSystem", Qt::QueuedConnection);
    exec();
}

void TimeBoundExerciser::exerciseTheSystem()
{
    cout << "Starting exerciser" << endl;
    exerciser();
    cout << "Exerciser ended" << endl;
}

The exercise() method is executed on the main thread to kick off the whole process.


If the test runs too long, it's probably in some sort of loop processing data.

Naturally, your quit request won't be delivered because the test thread is busy running the test. Messages don't interrupt threads, they are processed when the thread finishes processing the previous message and resumes the event loop.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜