[Development] What kind of airplane we want to build?
Marc Mutz
marc.mutz at kdab.com
Thu Jan 21 10:02:41 CET 2016
On Thursday 21 January 2016 02:02:11 Thiago Macieira wrote:
> On Thursday 21 January 2016 02:37:43 Marc Mutz wrote:
> > On Wednesday 20 January 2016 21:52:49 Thiago Macieira wrote:
> > > On Wednesday 20 January 2016 21:08:07 Pau Garcia i Quiles wrote:
> > > > Replacing QThread with std::thread? Please don't.
> > >
> > > Unlike the containers or even futures/promises vs QtConcurrent, we can
> > > easily argue that QThread provides a lot more functionality than
> > > std::thread. In just one word: signals.
> >
> > What happened to "you're doing it wrong!"? :) AFAIU that blog post,
> > you're supposed to use the signals of QObjects living in that thread,
> > not the QThread itself.
>
> You can use the signals and the slots of the QThread itself. The wrong part
> was deriving from QThread, adding slots to it and then doing
> moveToThread(this) so those slots got called in the thread that it manages.
>
> Other uses of QThread are fine. You can derive from it and override run.
> You can even add more signals to it. It's new slots that are suspicious.
Having had to teach this stuff to customers when this came out in Qt 4, I can
tell you this distinction will not register with most Qt-newbies. Allowing
such ease of wrong API use is against my reading Qt's own design principles
("make it hard to use an API incorrectly"). That QThread is a QObject is a
bug, not a featuee. It would be better as a non-QObject, adding QThreadWatcher
a la QFutureWatcher to enable singals. In that case, QThread can be replaced
with std::thread without much loss of generality.
> > And that's perfectly possible with std::thread, too:
> > auto po = new ProcessingObject();
> > connect(po, ...);
> > po->moveToThread(nullptr); // enable "pulling" moveToThread()
> > auto t = std::thread([po, gui = QThread::currentThread()]() {
> >
> > QEventLoop loop;
> > po->moveToThread(QThread::currentThread());
> > connect(po, ..., &loop, &QEventLoop::quit);
> > loop.exec();
> > po->moveToThread(gui);
> > // or: delete po;
> >
> > }
> >
> > Am I missing something?
>
> How do you interrupt the event loop from outside (QThread::quit)? You can't
> create that QEventLoop before the lambda because it would live in the wrong
> thread. You could use this:
>
> po->thread()->quit();
That's racy.
You could pass a shared_ptr<QEventLoop> by reference and use event posting to
avoid the race.
I'm not saying we don't need new API should we replace QThread with
std::thead. I'm saying that all the hard, impressive, work is already done. It
seems to be mostly a question of API now.
> but note how you used QThread. If you're going to use QThread anyway, you
> may as well use it to start the thread.
> Even if you didn't do this, your example uses QThread
> (QThread::currentThread(), which returns a QAdoptedThread pointer). And
> even if you didn't moveToThread(), you created a QObject in that thread
> (the QEventLoop), which will create the QThreadData and the event
> dispatcher machinery.
>
> At that point, QThread is a simple wrapper full of convenience functions.
>
I've used current API on purpose to show that it's possible already. All that
event loop, cross-thread signal/slots and event handling already works for
std::threads.
How we'd represent a thread if QThread was dropped is a different question, but
easily resolved once we get there (QThreadHandle, or even re-using QThread,
but not as a QObject subclass).
Thanks,
Marc
--
Marc Mutz <marc.mutz at kdab.com> | Senior Software Engineer
KDAB (Deutschland) GmbH & Co.KG, a KDAB Group Company
Tel: +49-30-521325470
KDAB - The Qt Experts
More information about the Development
mailing list