[Development] Evolving Qt's multithreading API

Sze Howe Koh szehowe.koh at gmail.com
Wed Feb 20 19:43:35 CET 2013


On 21 February 2013 00:29, Robert Knight <robertknight at gmail.com> wrote:
> 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.

Yes, C++ doesn't provide a way to interrupt a function block (there
wouldn't be a safe way to do so, anyway). The onus is on the
programmer to split their code into chunks/tasks, be it at a low level
(threading primitives) or high level (task-oriented programming)


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

I believe that the move-worker-QObject-to-thread approach aimed for
zero shared state -- all data is to be stored privately in the object,
and transferred between threads only via queued signals and slots.
Attempting to polish documentation/examples made me realize that we're
still somewhat divided on what approach to optimize for, hence the
start of this discussion :)

Tangent: I recently realized that task-oriented programming is
basically dataflow programming, which is inherently multithreaded.
Very powerful for data processing.


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

Agreed. TBB is looking quite attractive right now; do you have any
other recommendations?


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

Would it have been possible to encapsulate data within objects that
live in particular threads? I found that this approach worked quite
well for me. "I know it's safe for this object to work on this data,
'cos it's the only entity which can see it!" (granted, my projects
were small-ish)


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

Hmm... Data transferred through queued signals and slots are always
copied, if I'm not mistaken (unless it's a pointer -- the pointed item
isn't copied then). And the idea of signals/slots was to decouple the
sender from the receiver(s), so that they don't need to know about
each other. Can you give an example where the destination thread of my
emitted data would affect my program?


Regards,
Sze-Howe



More information about the Development mailing list