[Development] Evolving Qt's multithreading API

Sze Howe Koh szehowe.koh at gmail.com
Wed Feb 20 16:10:03 CET 2013


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



More information about the Development mailing list