PROPOSAL: Evolving Qt's multithreading API


  • Moderators

    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 immediately

    Advantages:

    • 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?


  • Moderators

    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...



  • 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?


  • Moderators

    [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.



  • JKSH - my apologies for polluting this stillborn thread. I hope I didn't stray it from its intended purpose :)


  • Moderators

    Apology accepted. I've grown accustomed to your polarizing sense of humour :) No, I doubt you've deterred anyone from commenting



  • I've added a link to this topic in the forum (but I missed the last digit in the link, fixed by the next poster) in a thread on this on the mailing list.


  • Moderators

    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.



  • I'd suggest you post those suggestions to the development mailinglist...


  • Moderators

    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 )


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.