[Development] Evolving Qt's multithreading API

Corentin Jabot corentin.jabot at gmail.com
Fri Feb 22 14:31:48 CET 2013


2013/2/22 Sze Howe Koh <szehowe.koh at gmail.com>:
> Yes, that was my original plan. Someone complained that they couldn't
> bind a function + arguments to QtConcurrent::run() first, then run it
> at a later time. This approach gives them the opportunity to start it
> whenever they want.

The problem is QtConcurrent does 2 separate things.
It binds function and run them asynchronously.

To me that's two different issues, so, if one want to bind a function
and run it later,
just use std::bind  ( hence my "QFunction" patch for c++03 support )


> On second thought, I'm not sure if this would be commonly needed. We
> can make it start immediately instead, BUT this requires a guarantee
> that the first thread can always connect the finished() signal, before
> the new thread runs and finishes. Can that be guaranteed?

Think about QNetworkAccessManager :
reply = nam->get(url); // start the request
connect(reply, QNetworkReply::finished(), doSomething()); // you can
connect later

I think that work just fine because the connection is queued,
But I'm not sure exactly how.


>If not,
>we'll need:
>
>     QThread *thread = QThread::runFunction([]() { return
> doSomethingComplicated(); });
>     connect(thread, &QThread::finished, this, &MyObject::doStuff);
>     thread->start(); // Manual start, after all connections have been made
>
> OR
>
>     QThread *thread = QThread::runFunction([]() { return
> doSomethingComplicated(); });
>     thread->wait(); // Wait for auto-started thread to end
>     doStuff();
>
> The latter is like Corentin's approach using QFuture. Which is better?
> (Personally I think the latter defeats the purpose of having a 2nd
> thread)

Of course that was a silly example, you would connect the QFuture
finished signal
to a slot, or use QFutureSynchronizer to run run multiple treatments
concurrently.


> Regarding deletion, we can follow the example of QAudioInput::start()
> -- it returns a pointer to a QIODevice for reading, but retains
> ownership of the device and auto-deletes it when stopped. Automatic
> deletion is needed to prevent a memory leak in the nice simple pattern
> you wrote above.


>
>> > > The implementation use the same sort of generator that QtConcurrent.
>> > > Thiago suggested making this feature only compatible C++11, which
>> > > would make it easier to maintain. I actually envisaged to send a mail
>> > > about that particular issue.
>> > > Can c++03 really be dropped for that particular feature ?
>> > > Also, I we were to make a c++11 only feature, what would be the
>> > > benefits over std::async ?
>> >
>> > I would love to see an implementation using C++11. I think that
>> > decision can't be made lightly though, and should be a separate
>> > discussion -- it has implications for all other Qt modules.
>>
>> What do you mean?
>> Do you mean an implementation of QThread that would use std::thread as an
>> internal rather than pthread/windows API? (qthread_cxx11.cpp)

Here again, two different issues.
1/ can we use the c++11 <functional> features and variadic templates
for the biding part.
2/ should we use the c++11 thread api somehow ( that looks like a huge
- unnecessary ? - change )

>>
>> I think it would be good to have. But would just be another layer, and more
>> code to maintain.
>
> I meant variadic templates and std::bind. QtConcurrent::run() uses a
> code generator to produce 6 separate templates. In theory, we can
> replace all that with 1 variadic template. No code generator, fewer
> templates, less maintenance.
>
>     template <typename TFunc, typename... TArgs>
>     static QThread* setupSimpleThread(TFunc&& func, TArgs&&... args)
>     {
>         // Private class, derived from QThread
>         return new QFunctionThread(
>                 std::bind(std::forward<TFunction>(a_func),
>                         std::forward<TArgs>(a_args)...));
>     }
>

Exactly, there are real benefits to use c++11 only.

> We do have many older compilers to support still. Is Qt ready to start
> introducing features that require C++11? Are we in a position to drive
> its adoption, as Thiago put it?
> (http://www.macieira.org/blog/2011/09/cxx11-support-in-qt-5/)

QtConcurrent somehow does works so people with no c++11 support, could
still use that even if its not ideal.


I was actually wondering if QtConcurrent couldn't be upgraded/recycled
    * adding QtConcurrent::runFunctionInNewThread(function, ...)
    * adding QtConcurrent::runFunctionInThreadPool(QThreadPool* p,
function, ... )
    * adding QtConcurrent::runFunctionInGlobalThreadPoool(function, ...);
    * deprecating QtConcurrent::run and make it an alias of
QtConcurrent::runInGlobalThreadPoool

This way, QThread keeps its current purpose of exclusively handling thread.

(Or we could add another class or namespace, like QAsynchronous,
reusing QtConcurrent would meant keeping c++03 compat and its suppose
we will still return QFuture)


About returning QThread* : what about the function return value ? That
should be accessible, easily.
It's one of the reason I prefer QFuture over QThread*


Regards,
Corentin



More information about the Development mailing list