Jongling models beetween threads

We know that in Qt the models are not thread-safe – they totally depend on your implementation.

So what we may do to bypass model between threads?
Guess that we have some models which implementation we can not adjust much or can not make thread-safe.
Danger is that if some model is used somewhere (pointer to model, saved QModelIndex, etc), then when we move model object to another thread, for some resource consuming processing, then some views or anything else may try to access it and you may get a crash.

But, there is one specific cool property that models have: they can be easily proxied.
Our idea is then that we make subclass of shared pointer (shared_ptr or QSharedPointer) and reimplement “->”. When some other object trys to access the smart pointer, it will get some proxy model (1:1 same data/structure/children/etc as source model).
Of course we have to use these smart pointers in all places where we would like to reference the model.

Moving the model to another thread (example for serialization or deserialization) is working in next way:
1. Call “detach()” on smart pointer – all other copies of smart pointers (we count them), will apply setSourceModel() to hidden proxy to use some stub single-cell model which is saying “Processing/Saving/Loading/…”
2. We bypass the real model to another thread “moveToThread()”, also send the smart_ptr with signal to holder in another thread
3. In another thread we do anything with model which is cpu/disc/etc consuming and may froze your UI if it were in GUI thread.
4. Send the smart pointer back to GUI thread, use “moveToThread()”
5. Call “attach” to attach our model to all smart pointer which got the model detached, then apply setSourceModel() to all hidden proxies.

In this way I implemented safe cpu/resource consuming operations on model datas while GUI was fully responsible!

This entry was posted in Blog, Boost, C++, Models, Qt. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

3 Comments

  1. Filipe AZEVEDO
    Posted January 19, 2014 at 17:13 | Permalink

    Is it possible to get a code example of the global implementation ?

  2. Kuba Ober
    Posted January 31, 2014 at 21:37 | Permalink

    There’s nothing fundamentally thread-unsafe about a `QAbstractItemModel`. If you only access the model from views, then the model doesn’t have to be in the gui thread and it “just works”. Simply use `moveToThread` on the model and you’re done. If you want to call the model’s methods from your own code, you need to use `QMetaMethod::invoke`. That’s about it. You’re horribly overcomplicating things for no reason at all.

  3. Kuba Ober
    Posted January 31, 2014 at 21:40 | Permalink

    If you want, you can make a proxy model that uses `QMetaMethod::invoke` when the `sourceModel()->thread() != QThread::currentThread()`, otherwise it’d do direct calls to the source model. It also works great. This exposes a fully thread safe interface to a model, and can be accessed from any thread.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>