PROPOSAL: Evolving Qt's multithreading API
-
Hi all,
h1. Background
I've been thinking about Qt's multithreading API. Currently, Qt's suggestions for multithreading are:
- Subclass a worker QObject and move it to a QThread (if an event loop is desired)
- Subclass QThread^ (if an event loop is not desired AND recycling QThreads is not desired)
- Subclass QRunnable and attach it to a QThreadPool (if an event loop is not desired AND recycling QThreads is desired)
- Call QtConcurrent::run() (if a parallel function call is desired AND recycling QThreads is desired)
- Use QtConcurrent's filter-map-reduce API (if high-level container processing is desired)
(^The Qt Project community is divided on this; some discourage all subclassing of QThread, but Qt's maintainers say it's valid in some cases)
Current shortcomings:
The API is quite disparate; the code for the different approaches don't look like they come from the same library. Furthermore, some features are missing:- The ability to do a parallel function call, or use QRunnable, without being tied to a thread pool
- The ability to emit a signal when a thread finishes a QRunnable
- The ability to delay a parallel function call
- The ability to elegantly separate code control and thread logic (hence the long-running "Subclass QThread or not?" debate)
h1. Proposal
So, here are some proposed additions to the QThread and QThreadPool classes, to make the API it more unified and flexible:
@
class QThread
{
...
public:
/1/ static QThread* setupSimpleThread(QRunnable* runnable);
/2/ static QThread* setupSimpleThread(Function func, ...);
/3/ static QThread* setupEventLoop(QObject* worker);
};class QThreadPool
{
...
public:
/4.1/ void start(Function func, ...);
/4.2/ void start(int priority, Function func, ...);
/5/ bool tryStart(Function func, ...);
void start(QRunnable* runnable, int priority = 0); // Already exists
bool tryStart(QRunnable* runnable); // Already exists
};
@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 immediatelyAdvantages:
- The missing features mentioned earlier are provided
- A symmetrical API for using both recycled and unrecycled threads -- QThreadPool and QThread
- A unified API, which clearly distinguishes and enforces the 2 different approaches to using QThread -- both with and without an event loop
- A clean separation between thread control (QThread) and threaded code (QRunnable), thus making it more idiot-proof. Also achieved without the huge overhead of the worker-object approach
h1. Demos
Want to use signal-slot connections across threads? Set up a parallel event loop:
@
class WorkerObject : public QObject {...};WorkerObject *worker = new WorkerObject();
QThread *thread = QThread::setupEventLoop(worker);
connect(...)
thread->start();
@Don't want to subclass QThread, but don't want to put up with the code+runtime overhead of a worker QObject either? Subclass QRunnable instead:
@
class MyRunnable : public QRunnable {...};QThread *thread = QThread::setupSimpleThread(new MyRunnable(...));
connect(thread, SIGNAL(finished()), ...); // end-of-QRunnable signal!
thread->start();
@Want to run a "single-shot" function in a separate thread? Take your pick:
@
void myFunc(int arg1, float arg2) {...}QThread *thread = QThread::setupSimpleThread(&myFunc, 123, 45.6);
connect(thread, SIGNAL(finished()), ...);
thread->start();// OR, to recycle threads,
QThreadPool::globalInstance()->start(&myFunc, 123, 45.6);
@h1. Request for feedback
What do you think? Is this a worthwhile addition to Qt? Which of (4.1) and (4.2) are better? Is there anything missing?
-
Bump! :)
-
I think it would be better to discuss this in the development@qt-project.org mailing list.
-
I find it paradoxical that a mailing list is considered to be a better place for a DISCUSSION than a DISCUSSION BOARD...
Come on, mailing lists stopped being adequate about a decade ago... why all that lingering in the past, especially on something that is actually concerned with the future development?
-
[quote author="utcenter" date="1361280609"]I find it paradoxical that a mailing list is considered to be a better place for a DISCUSSION than a DISCUSSION BOARD...
Come on, mailing lists stopped being adequate about a decade ago... why all that lingering in the past, especially on something that is actually concerned with the future development?[/quote]
Blah, blah, blah... This is not a discussion about the merrits of forums versus mailinglists. Start your own topic in the Lounge forum if you want to discuss that. The fact of the matter is that most development related discussions on Qt are done in the mailing list I mentioned, and so I am suggesting to post the proposal there instead of on this forum. This forum mostly attracts Qt users, not Qt developers. Alternatively, I could point to the relevant IRC channel, but I guess that that is really out of what you find an acceptable channel...
-
[quote author="Andre" date="1361276770"]I think it would be better to discuss this in the development@qt-project.org mailing list.[/quote]I plan to do that soon. I thought I'd also ask potential users of the API :)
[quote author="utcenter" date="1361284937"]There actually was a thread on this particular topic started by another user, but it didn't catch much attention, probably because it wasn't in the mailing list D'OH ;) ... mailing lists... irc... what's next? Punched cards? The phonograph? [/quote]Not helpful.
-
Apology accepted. I've grown accustomed to your polarizing sense of humour :) No, I doubt you've deterred anyone from commenting
-
Thanks Andre. For the mailing-list inclined, the post is at http://lists.qt-project.org/pipermail/development/2013-February/009970.html
-
BTW, it might be useful to get something like M$'s Parallel.For to speed up lengthy loops. On a related note, some portable explicit vectorization facilities would be nice too, with implementation for major SIMD engines like SSE, AVX, Neon, and naturally a fallback to software if none are present.
-
My proposal was simply for optimizing the API, without changing the internals of the library. Implementing parallel loops and processor-level optimizations is out of my league.
But anyway, there's some talk about integrating a 3rd-party library -- which DOES offer such features -- into Qt, to reduce the workload on Qt's side (http://lists.qt-project.org/pipermail/development/2013-February/009968.html )