Search code examples
c++multithreadingqtqabstracttablemodelqmutex

using data shared between multiple threads in a QAbstractTableModel


I have a singleton class implemented using Q_GLOBAL_STATIC that contains a data structure that has to be accessed from multiple threads, I implemented accessor functions in the class, that would lock a mutex before accessing the data, so that all accesses to the shared data are serialized.

The problem is that I want to use this data in a QAbstractTableModel, I can simply use the accessor functions I implemented and access one item at a time from my overridden data(), columnCount() and rowCount(). But I think this is insufficient, since between two subsequent calls to data() another thread may jump in and change the number of items for example (rowCount()), and the model's thread may end up accessing out of bounds data.

I think I need to lock the mutex before the very first call of columnCount() and rowCount() of the model reset, and unlock it only when all data is read into the model (after the last call to data()), is there a way to do so? or am I thinking the wrong way?

I thought of copying the shared data structure to a local one on model reset(and have the mutex locked only on the copy operation), and after that access the copied data safely, but isn't that an overkill? isn't there a more efficient solution?


Solution

  • In Qt's Model-View framework, the interface between QAbstractItemModel and QAbstractItemView is not threadsafe at all, it is designed to be used with only one thread, which must be the GUI thread, i.e. the main thread since view does painting on the GUI, which cannot be done securely in another thread than the main (GUI) thread.

    Therefore a model must hold it's own data and synchronize it with real data. If your dataset is large, you can rely on fetchMore() to avoid copying the whole data in every model instance. See what is done in QtSql's sql models code. Then the lock-between-calls issue you raise is easier to solve.

    You can even update the model in an event-driven way if the real data holder objects are able to emit signals connected to the model instance. Thanks to auto/queued signal connections, the model slots will execute in the main (GUI) thread and therefore won't need to be threadsafe with the QAbstractItemModel-QAbstractItemView interface.