[Development] Evolving Qt's multithreading API

Robert Knight robertknight at gmail.com
Wed Feb 20 17:29:21 CET 2013


One other thing - QtConcurrent::run(), QRunnable and invokeMethod() do not
provide any standard mid-task cancellation mechanism, which I've found to
be a very common need in the context of a client app which is offloading a
chunk of heavy work to background threads to avoid UI lag - eg. file
operations, parsing.  QFuture provides a cancel() method and a QThread's
event loop can be quit between processing events but these only work
between task execution.

Regards,
Rob.


On 20 February 2013 16:24, Robert Knight <robertknight at gmail.com> wrote:

> Hello,
>
> A few thoughts:
>
> - In general and especially for newcomers, encourage task-orientated
> concurrency and avoiding shared state where possible.
> This partly about documentation and the examples but also in the kind of
> approach that the APIs optimize for.
>
> - Having had the er, pleasure of debugging a number of concurrency issues
> in QThread, ThreadWeaver and other third party libraries over the years, I'd
> say there is a very strong case for going with a wrapper around a
> well-written and tested existing library where possible.
>
> A few years back I tended to use the 'create object, move to thread, send
> messages' approach to doing background work.
> The problem is that it usually isn't explicit enough when reading the code
> what data a particular thread can or cannot safety access.
>
> With cross-thread signals, you have the issue that when you emit a signal,
> it isn't immediately clear at that point that you may be
> sending data to another thread - depending on who happens to be
> listening.  If you see that a value is being written into a channel on
> the other hand - as you would find in Go or Rust, it is much more explicit
> that the value or reference is being passed to another thread for use.
>
> Regards,
> Rob.
>
>
> On 20 February 2013 15:10, Sze Howe Koh <szehowe.koh at gmail.com> wrote:
>
>> On 20 February 2013 22:49, André Somers <andre at familiesomers.nl> wrote:
>> > Op 20-2-2013 15:45, Sze Howe Koh schreef:
>> >> Hi all,
>> >>
>> >> Some time ago there was some talk about improving Qt's multithreading
>> >> API. I'm summarizing them here to stop them from fading into
>> >> obscurity, and to see if there's any interest in following them up.
>> > There is also a proposal posted here:
>> > http://qt-project.org/forums/viewthread/2488
>> >
>> > André
>>
>> André meant http://qt-project.org/forums/viewthread/24884/ :-)
>>
>> I'd like to add this idea to the mix: Give Qt's low-level API more
>> flexibility and consistency.
>>
>> Currently, Qt's suggestions for multithreading are:
>>
>> - Subclass a worker QObject and move it to a basic QThread (if an
>> event loop is desired)
>> - Subclass QThread (if an event loop is not desired)
>> - Subclass QRunnable and run it via a QThreadPool (if recycling
>> QThreads is desired)
>> - Call QtConcurrent::run() (if a parallel function call is desired)
>> - Use QtConcurrent's filter-map-reduce API (if high-level container
>> processing is desired)
>>
>>
>> Ignoring filter-map-reduce (the only true high-level option here), the
>> low-level API looks quite disparate. Furthermore, some features are
>> missing:
>>
>> - The ability to use QRunnable, or make a parallel function call,
>> without being tied to a thread pool
>> - The ability to emit a signal when a thread finishes with QRunnable
>> - The ability to delay a parallel function call
>> - The ability to elegantly separate code control and thread logic
>>
>>
>> === PROPOSED NEW METHODS ===
>> 1) static QThread* QThread::setupSimpleThread(QRunnable *runnable);
>> 2) static QThread* QThread::setupSimpleThread(Function func, Args arg,
>> ...);
>> 3) static QThread* QThread::setupEventLoop(QObject* worker);
>>
>> 4) void QThreadPool::start(Function func, Args arg, ...);
>> 5) bool QThreadPool::tryStart(Function func, Args arg...);
>>
>>
>> === BEHAVIOUR ===
>> (1) binds a QRunnable to a QThread, which will call the
>> QRunnable::run() when start()'ed.
>> (2) binds a function and zero or more arguments to a QThread, which
>> will call the function when start()'ed.
>> (3) moves the worker QObject to the new thread, ready to have its
>> slots invoked when the QThread is start()'ed.
>> (4) and (5) are similar to (2), but it uses a recyclable thread from a
>> QThreadPool and (tries to) start immediately
>>
>>
>> === ADVANTAGES ===
>> - The missing features mentioned earlier are provided
>> - A symmetrical API for using both recycled and unrecycled
>> threads(QThreadPool and QThread)
>> - A unified, self-documenting API, which clearly distinguishes and
>> enforces the 2 different ways to using QThread (both with and without
>> an event loop)
>> - A way to cleanly separate thread control (QThread) and threaded code
>> (QRunnable), thus making it more idiot-proof. Also achieved without
>> the huge overhead of the worker-object approach
>>
>>
>> === IMPLEMENTATION ===
>> (1) The QThread implementation can be similar to QThreadPoolThread,
>> except that it doesn't check the number of active threads.
>> (2, 4, 5) Ideally, we'd use a variadic template with std::function +
>> std::bind behind the scenes. But, since C++98 support is required, I
>> guess we'll have to follow QtConcurrent::run()'s approach (multiple
>> overloaded templates for different numbers of arguments).
>> (3) setupEventLoop() is just a simple wrapper that instantiates a
>> basic QThread and calls moveToThread() on the worker, before returning
>> the QThread.
>>
>>
>>
>> Thoughts?
>>
>> Regards,
>> Sze-Howe
>> _______________________________________________
>> Development mailing list
>> Development at qt-project.org
>> http://lists.qt-project.org/mailman/listinfo/development
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20130220/abe19273/attachment.html>


More information about the Development mailing list