Bug report #13234
QgsMessageBar crash qgis in mutithread context
Status: | Closed | ||
---|---|---|---|
Priority: | High | ||
Assignee: | - | ||
Category: | - | ||
Affected QGIS version: | 2.8.3 | Regression?: | No |
Operating System: | Easy fix?: | No | |
Pull Request or Patch supplied: | No | Resolution: | invalid |
Crashes QGIS or corrupts data: | Yes | Copied to github as #: | 21295 |
Description
During test thread management in a plugin I created a test plugin to calibrate the user communication from the thread.
I created a QgsMessageBarItem and set it's message, and when the thred finish I remove the QgsMessageBarItem from message bar and I push a new message notifying the result.
During removing the item, the item it's still valid and will arrive also a message notify that does not find a valid object => qgis crash
Attached you can find the simple test plugin that crash qgis... just run it press ok in the simple dialog, the thread will start notify message in the messageBar... then after 10 pings will crash (in my case)
tested on 2.8.3 and qgisMaster... both cases compiled versions.
QGIS version 2.8.3-Wien QGIS code revision 1207e38
Compiled against Qt 4.8.6 Running against Qt 4.8.6
Compiled against GDAL/OGR 1.11.2 Running against GDAL/OGR 1.11.2
Compiled against GEOS 3.4.2-CAPI-1.8.2 Running against GEOS 3.4.2-CAPI-1.8.2 r3921
PostgreSQL Client Version 9.4.4 SpatiaLite Version 4.1.1
QWT Version 5.2.3 PROJ.4 Version 480
QScintilla2 Version 2.8.3 This copy of QGIS writes debugging output.
History
#1 Updated by Nathan Woodrow about 9 years ago
- Assignee deleted (
Nathan Woodrow)
My guess is that you are calling the message bar directly from inside your thread? If so you can't alter GUI from a non UI thread. You will need to have a signal on your thread to notify the UI and show the message bar there.
#2 Updated by Nathan Woodrow about 9 years ago
- Tag changed from QgsMessageBar crash thread to crash thread
- Resolution set to invalid
Here is an example:
from PyQt4.QtCore import QThread, QObject, pyqtSignal
class Worker(QObject):
done = pyqtSignal()
finalResult = pyqtSignal(int)
def __init__(self, parent=None):
super(Worker, self).__init__(parent)
def do_stuff(self):
l = 0
for i in range(100):
l += i
self.finalResult.emit(l)
self.done.emit()
def cleanup(self):
pass
def result(value):
iface.messageBar().pushMessage("Done", str(value))
thread = QThread()
worker = Worker()
worker.moveToThread(thread)
worker.done.connect(thread.quit)
worker.finalResult.connect(result)
thread.started.connect(worker.do_stuff)
thread.finished.connect(worker.cleanup)
thread.start()
#3 Updated by Luigi Pirelli about 9 years ago
in the proposed code the worker.run does not have gui interacion... it emits only signals. These are received by the plugin at the same instance level where the Thread is created and started and the worker (Algorithm) is passed.
I'll try more tests adding also thread.finished and movind thread release there
#4 Updated by Nathan Woodrow about 9 years ago
That's right. You can't alter the UI in a non UI thread. So worker can't alter the UI it has to talk via signals.
#5 Updated by Luigi Pirelli about 9 years ago
- Status changed from Open to Closed
crash seems not related with thread but:
iface.messageBar().popWidget(self.progressMessageBarItem)
-->> self.progressMessageBarItem.deleteLater()
I can't deleteLater QgsMessageBarItem because already removed by popWidget (http://qgis.org/api/qgsmessagebar_8cpp_source.html#l00174)
#6 Updated by Luigi Pirelli about 9 years ago
I'm not a sip expert.. but could be a problem in the python binding specification for the QgsProgressBar items ownership?
https://setanta.wordpress.com/binding-c/
regards