[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