0

So I have the following situation:

I have a QThread that runs an eventloop (i.e. no custom run function). To stop the thread, I send a signal to a worker in that thread. This worker then does cleanups etc and at some point is done and quits the thread.

The problem I am facing right now is: If I invoke the workers stop method and then immediatly wait for the thread to finish it will never do so because the workers done signal does not get processed. Code:

class Worker {
signals:
    void done();

public slots:
    void stop() {
        //dummy code to illustrate what happens here:
        QTimer::singleShot(3000, this, &Worker::done);
    }
};

// in the main thread
auto thread = new QThread();
auto worker = new Worker();
worker->moveToThread(thread);
connect(worker, &Worker::done, thread, &QThread::quit); //implicitly a queued connection

// ...

QMetaObject::invokeMethod(worker, "stop", Qt::QueuedConnection);
thread->wait(); //blocks here forever, because the connect is queued

Now reason the problem is obvious - Because I block on the main thread the slot can never be invoked (because queued connection) and thus quit is never called. However, if I simply call QThread::quit (or QThread::exit) directly from the worker (or use a DirectConnection) then there is no problem anymore because the eventloop of the main thread is no longer required to process the event.

So the actual question here is: Is that allowed? Can I call QThread::quit from within the actual thread? Or can this create Race conditions, deadlocks and other problems like that. The documentation does not mark the method as threadsafe - but the thread that is managed by QThread might be an exception.

2 Answers 2

2

If you look in the file src/corelib/thread/qthread.cpp in the Qt source folder, you can see how quit() is implemented:

void QThread::quit()
{ exit(); }

.... and QThread::exit() is definitely intended to be called from within the thread itself. So the answer is yes, it's fine to call quit() from within the QThread's thread (although it might be a bit more usual to just call QThread::exit() directly instead).

Sign up to request clarification or add additional context in comments.

1 Comment

I just checked the sources myself and QThread::exit uses a mutex - which at least hints that it should be fine. Still, it's something that should be explicitly stated in the documentation...
1

Can I call QThread::quit from within the actual thread?

The question is actually backwards!

Since this method controls the event loop, and the event loop most definitely runs on the thread, the default assumption is that it's not a thread-safe method and thus can only be called from within the thread, since it controls a QEventLoop instance instantiated via QThread::run. That event loop, and its event dispatcher, are QObjects and most definitely have their thread() equal to the QThread instance in question.

But that wouldn't make QThread very useful, and thus QAbstractEventDispatcher::exit, and thus QEventLoop::quit and QThread::quit, are indeed thread-safe methods - you can call them from wherever, including from threads other than the one where the event loop lives. Both the event loop and thread's methods take extra precautions to protect their state from races, so the "and thus" part a few sentences ago is hand-wavey a bit.

5 Comments

@m7913d No, but the world would stop if it weren't so. I mean, a lot of Qt-using code would break if this method was not thread safe - because it shares code paths with things where lack of thread safety would break stuff. The source code is the documentation. You need to use a Qt debug build (you always should anyway when you debug stuff), with sources installed, and step through this method, and see what it does. Because of how any interaction with the event loop would work, it has to acquire locks, and is thus thread-safe.
If you artificially undo thread safety from the event loop control paths, Qt Creator crashes/freezes almost immediately - I'm just using Creator as an example of a large Qt application here, since I happen to build it from source along with Qt and can easily introduce changes. IOW: If Qt Creator works for you (and if KDE works, ...), then the method is thread-safe. It's a fundamental requirement. It's an OSS project, do feel free to contribute a documentation change that clarifies this! It won't happen automagically. Someone has to do it. Qt docs aren't set in stone.
I definitely agree, I was just wondering if it was documented. I created a bug report: bugreports.qt.io/browse/QTBUG-86112
Nonono, don't just create a bug report. There's no manpower to deal with such stuff. You have to fix it yourself. I'm serious. Get your contribution in, and close that bug report yourself :)
Sorry, but I do not have experience with submitting bug fixes, maybe you can fix this part of the docs?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.