QAbstractListModel populated in a Worker Thread (not the GUI one)?
-
The easiest solution is to simply pass the data from the worker to the gui thread and do the insertion to the model there. Everything else will lead to problems sooner or later.
-
The easiest solution is to simply pass the data from the worker to the gui thread and do the insertion to the model there. Everything else will lead to problems sooner or later.
@Christian-Ehrlicher well what's bothering me is that we then need to make at least one copy of the data received by the worker...
The worker receives data on its own structure, it then need to send a copy of it via a signal, and then the GUI thread will copy (or move) this into its own structure. It doesn't look really efficient.
For now, I've moved back my ConnectionWorker in the main Thread and it's working just fine.
As the Sockets are asynchronous, I suppose I could keep this architecture.Anyway, I'd like to know if it is possible to publish PROPERLY the data of Models in another Thread and if so what are all the steps required. Where do we need Mutex synchronisation on the Model side?
I've seen there are those for private signals in
QAbstractItemModel
:void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last, QPrivateSignal); void rowsInserted(const QModelIndex &parent, int first, int last, QPrivateSignal); void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal); void rowsRemoved(const QModelIndex &parent, int first, int last, QPrivateSignal);
Would it be a way to listen on them in the View and lock any redraw during the AboutTo signal and the Complete one?
-
I don't see why you need to copy your data a second time. Fetch them in the worker, send a signal to notify the model that there is new data, let the model copy the data into the internal structure. Why do you want to pass the data via signals/slots?
Anyway, I'd like to know if it is possible to publish PROPERLY the data of Models in another Thread and if so what are all the steps required. Where do we need Mutex synchronisation on the Model side?
No
-
I don't see why you need to copy your data a second time. Fetch them in the worker, send a signal to notify the model that there is new data, let the model copy the data into the internal structure. Why do you want to pass the data via signals/slots?
Anyway, I'd like to know if it is possible to publish PROPERLY the data of Models in another Thread and if so what are all the steps required. Where do we need Mutex synchronisation on the Model side?
No
@Christian-Ehrlicher said in QAbstractListModel populated in a Worker Thread (not the GUI one)?:
I don't see why you need to copy your data a second time. Fetch them in the worker, send a signal to notify the model that there is new data, let the model copy the data into the internal structure. Why do you want to pass the data via signals/slots?
Hum true, I just need a Mutex in the Worker to lock its internal structure (in case he would receive a new one). I'm going to try. Thanks :)
@Christian-Ehrlicher said in QAbstractListModel populated in a Worker Thread (not the GUI one)?:
No
Alright that's a categoric answer! Is it published somewhere in Qt documentation?
-
I don't see why you need to copy your data a second time. Fetch them in the worker, send a signal to notify the model that there is new data, let the model copy the data into the internal structure. Why do you want to pass the data via signals/slots?
Anyway, I'd like to know if it is possible to publish PROPERLY the data of Models in another Thread and if so what are all the steps required. Where do we need Mutex synchronisation on the Model side?
No
@Christian-Ehrlicher said in QAbstractListModel populated in a Worker Thread (not the GUI one)?:
I don't see why you need to copy your data a second time. Fetch them in the worker, send a signal to notify the model that there is new data, let the model copy the data into the internal structure. Why do you want to pass the data via signals/slots?
Well in fact, I'm receiving the data in the Worker from a Socket and filling a QBuffer (cf here) until the data is complete and ready to be processed.
If I'm signalling the main Thread to process the data, it means I need to copy this QBuffer...
It doesn't look that a QBuffer is movable...
Don't know if it has implicit sharing...
So I'd end up making at least 1 copy if I don't want to lock my Connection Thread to let it receive other request.
Am I missing something? -
@mbruel said in QAbstractListModel populated in a Worker Thread (not the GUI one)?:
Alright that's a categoric answer! Is it published somewhere in Qt documentation?
Not directly - when you can fix all the issues with the begin/end stuff it may work so my 'No' is my personal opinion from working with the models and views for a long time (and fixing bugs for them within Qt) - it's just not worth the trouble (and I'm sure @VRonin and others will tell you the same).
-
@mbruel said in QAbstractListModel populated in a Worker Thread (not the GUI one)?:
Alright that's a categoric answer! Is it published somewhere in Qt documentation?
Not directly - when you can fix all the issues with the begin/end stuff it may work so my 'No' is my personal opinion from working with the models and views for a long time (and fixing bugs for them within Qt) - it's just not worth the trouble (and I'm sure @VRonin and others will tell you the same).
@Christian-Ehrlicher
ok cool,
I've updated my code and remove the QBuffer to use directly QByteArray.
In fact no need to move it, as I'm using protobuf (not my choice) and that they are movable.
So I'm doing this from the Worker:case pb::remote::LIST_FILES: #ifdef __USE_CONNECTION_THREAD__ _secureRemoteFiles.lockForWrite(); _remoteFilesData = std::move(msg); emit remoteFilesUpdatedByWorker(); #else rcvListOfRemoteFiles(msg.response_files()); #endif break;
and I can just do the model update back in the GUI thread without any copy! \o/
void ClementineRemote::onRemoteFilesUpdatedByWorker() { rcvListOfRemoteFiles(_remoteFilesData.response_files()); _remoteFilesData.clear_response_files(); _secureRemoteFiles.unlock(); }
Indeed not worthing the trouble of updating the Model directly in the Worker Thread.
But if it should work nicely, it would be nice to know how ;) -
Nice to see it working with this easy solution. I already wanted suggest you to create the data with new so you only need to copy the pointers.
Updating the model directly from another thread is really hard - it would require a mutex in every function in your model and you must somehow execute the begin/end functions in the main thread.
-
Nice to see it working with this easy solution. I already wanted suggest you to create the data with new so you only need to copy the pointers.
Updating the model directly from another thread is really hard - it would require a mutex in every function in your model and you must somehow execute the begin/end functions in the main thread.
@Christian-Ehrlicher said in QAbstractListModel populated in a Worker Thread (not the GUI one)?:
Nice to see it working with this easy solution. I already wanted suggest you to create the data with new so you only need to copy the pointers.
yep that wasn't so hard, not sure why I was thinking I would need to send the structure inside the signal...
@Christian-Ehrlicher said in QAbstractListModel populated in a Worker Thread (not the GUI one)?:
it would require a mutex in every function in your model
that would be great to have the list. I thought those two would be enough for a read only Model in the View:
int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
@Christian-Ehrlicher said in QAbstractListModel populated in a Worker Thread (not the GUI one)?:
somehow execute the begin/end functions in the main thread
Well I don't see how to manage that if it's the Working Thread that updates the data...
Doing some synchronisation in order to achieve it would be just less efficient than letting the main thread updating the data...Any expert in the area to learn how to achieve it? @VRonin maybe?
-
@mbruel said in QAbstractListModel populated in a Worker Thread (not the GUI one)?:
Well I don't see how to manage that if it's the Working Thread that updates the data...
Doing some synchronisation in order to achieve it would be just less efficient than letting the main thread updating the data...Correct, therefore my recommendation - don't try it :)