Alex Rivera | Logout

How to properly interrupt a QThread infinite loop

Asked 2011-02-04T12:23:16.793
12

I'm done implementing a Go program where the human can interrupt at any time the software to order it to play. Basically, I've got an algorithm running in another thread that has at every moment a "Best move" available, that it keeps on improving.

My question is : how do I correctly interrupt a thread in an infinite loop?

I've tried a few things, and resolved to do this :

class MyWorker : public QObject
{
    Q_OBJECT
public:
    MyWorker();
    ~MyWorker();

public:
    ThreadControl * getThreadControl();

public slots:
    void work();

private:
    void endOfComputation();

private:
    ThreadControl * threadControl;
}

Notice that I don't subclass QThread:

class ThreadControl : public QObject
{
    Q_OBJECT
public:
    ThreadControl();

public:
    bool getAbort();
    Parameter getParameter();
    void setParameter(Parameter & param);

public slots:
    void setAbort(bool b);

private:
    QMutex mutex;
    bool abort;
    Parameter param;
};

And, finally, the infinite loop is coded as this :

void Myworker::work()
{
    // ...
    forever
    {
        abort = threadControl->getAbort();
        if(abort)
        {
            break;
        }
        // ...
    }
    endOfComputation();
}

Then, as you can guess, in the main, I regularly call ThreadControl::setAbort(true)

Basically, I just keep a pointer to a boolean in the main thread and I toggle it when I want to. (The boolean is encapsulated in ThreadControl so I can properly lock it with a mutex). So far so good, it has worked for me... But it seems disgusting to me! Toggling pointers to booleans sound like ... bad programming to me...

The problem is the documentation on the web is mostly (entirely?) about producers a

Edit
Report

1 Answer

7

I understand that toggling flags instead of calling some sort of specialized methods looks ugly, but in real life it's the best way to do it. Specialized methods are usually very dangerous, see QThread::terminate() for example. Some environments provide ready-to-use flags so you don't have to add your own booleans, like Java with its Thread.interrupt() and Thread.interrupted(). Qt has no such thing, and maybe that's good too because interrupting sometimes works kind of counter-intuitively in Java. Take the difference between Thread.interrupted() and Thread.isInterrupted() for example. It is absolutely counter-intuitive. Unless you consult the docs, you can hardly guess what's the difference. Worse, since one of them is static, you may think that's the difference, but it's not. Also, old-style IO operations can't be interrupted in Java, but new-style NIO can, which makes no sense either.

Sometimes you can avoid flags by using something else. For example, if a thread has some sort of input queue of elements to process, you could use a special end-of-queue element to indicate that it should stop right there. But sometimes there is no convenient place to put this, that's when you use boolean flags.

The only thing you could do to optimize your code a bit is to replace mutex locking with a volatile bool. This will not guarantee memory access ordering, though, so if your thread depends on something that happens around volatile write, you shouldn't go this way. Or you could use a QAtomicInt instead with its memory barriers. But if there is no significant performance impact, using a mutex is fine, and safest too.

I'd also replace the loop with:

while (!threadControl->getAbort()) {
  // ...
answered 2011-02-04T13:45:47.247

Your Answer