[Development] Evolving Qt's multithreading API

André Somers andre at familiesomers.nl
Mon Mar 4 17:25:35 CET 2013


Op 4-3-2013 16:17, Sze Howe Koh schreef:
> On 2 March 2013 18:17, Andre Somers <andre at familiesomers.nl> wrote:
>> Actually, how do you feel about adding an optional _then_ argument to
>> the list of arguments of the functions in QtConcurrent and whatever is
>> decided to replace the QtConcurrent::run feature? Such a _then_ argument
>> could be a slot signature, a function pointer or a lambda function
>> (basically, whatever you can use in the Qt 5 QObject::connect). That
>> would make it quite a bit easier to work with, I think. It would
>> eliminate the need to create (and delete) a QFutureWatcher for a lot of
>> cases. The method you passed into the _then_ argument would be called
>> when the future is ready. It would be very nice if the _then_ argument
>> could optionally have an argument of the return type of QFuture::result.
>>
>> For this to work, QFuture would not need to be a QObject itself, and
>> because you pass in the _then_ argument with the call itself, you don't
>> have the race issues that you get if you need to connect in separate
>> calls after you have already fired off the thread: no need for
>> trampoline objects or the like.
> Do you mean like the last argument to QTimer::singleShot()? (this
> needs to be updated to support Qt 5 slots, by the way)
Yes, very much like that, but updated to also support the Qt5 like way 
of connecting.
> Yes, that could work. To make it truly optional though, the main
> parallel function would have to be pre-bound by the programmer (e.g.
> using https://codereview.qt-project.org/#change,45294), since the
> argument list is variable-size.
>
>      QFuture<T> runFunction(QFunction<T> main, QFunction<S> then = NullFunction);
>
> Would the extra binding step nullify the convenience of not requiring
> a signalling object?
It would not quite, but it would be a bit of a let-down. There still is 
the benefit of not having to worry about race conditions. However, if we 
modify the syntax a little bit, I think we can avoid the additional 
binding step:

QFuture<T> runFunction(QFunction<T> then, QFunction<T> main);
QFuture<T> runFunction(QFuntion<void> then, QFuntion<T> main);
QFuture<T> runFunction(QFunction<T> main);

(Copying your use of QFunction, a quick look at the WIP you mentioned 
doesn't quite reveal to me how it is supposed to work, and I probably 
use it wrong. The then argument could be lambda function, a QObject* and 
a slot signature, a pointer to an object and a member function pointer, 
or perhaps even a plain function pointer. It would be nice if the 
argument for these could be either no argument at all, or of the type T 
so it can just receive the value from the method.)

Sure, it would read easier to have the _then_ follow the actual method, 
if if that is not possible, then I would not mind having them be reversed.

However - and I am not a template mage - I think it should be possible 
to keep the order as is? As long as the actual function doesn't take a 
final argument with the given signature, I don't think there would be 
confusion?

Note that I'd also like to see the same possibity for the other 
QtConcurrent methods, and pershaps even the threadpool method as well.
> Or, what if the run-function returns a QFutureWatcher which already
> has a QFuture attached -- would that ease the burden from the
> programmer a bit?
No, it would not!
The returned QFutureWatcher then has unclear ownership. That sounds even 
worse than having to create one yourself. And: the future still can 
finish before you have a chance to make the connection between the 
QFutureWatcher::finished() signal and your own slot.
> It's such a shame that template classes can't be meta-objects...
> otherwise we could emit the return value directly. That would truly be
> event-driven C++!
Yeah, that is a very unfortunate artifact of the way Qt implements 
signals and slots. However, it is what it is...

André




More information about the Development mailing list