Silent exit from qt program
-
wrote on 31 Jul 2022, 08:43 last edited by devnul
Hi all, I have a large app which silently quits (no python stack trace) seemingly at random.
I've run with fault handler enabled and the trace tells me that the panic/exit occurs in the qt mainloop somewhere. The app is multi threaded, but does use appropriate signal slot communication and all qt action happens in slots in the main thread. This is because all other threads are sleeping at the time of exit!
I believe that my code is breaking something inside the qt runtime. I am looking for advice, how to spot patterns that may cause bad behavior. I was thinking for example, in c++ a dangling pointer after a free, would cause issues like this, or a null pointer being passed around unchecked. BUT I am in python. Hard to know when something like that happens.
Has anyone got any advice? What should I look out for? Parents set to None? Etc? I'm not were where the line between python and qt could get this messy but clearly something I'm doing is bad.
Just looking for pointers :) I'm quite new to qt.
I'm using python 3.10, and PySide6, PyQtgraph, but not alot else.
Thanks!
-
Hi,
On which OS are you ?
What does your application do ? -
wrote on 1 Aug 2022, 05:21 last edited by
@SGaist, windows 10 only, we test on windows 11 also but there seem to be issues there for now.
The application is a configuration and monitoring tool for a hardware product. We simply poll data from a USB comport, the data rate is around 320kbps or so but varies.
We push this data through a pubsub system, the entire publishing run is actioned once per 100ms in the main thread (by qt in a slot). Presently the data stream can service 1000 unique parameters, but at any time there might be around 50 or so on screen so it's not as intense as all that. The most immediately concerning thing to me is that out of these 1000 Parameters, we allow the user to configure any one of them on screen. This means there can be many, many widget create and delete cycles per session.All of that said, the program will exit at times when there is almost nothing on screen, just a qtreeview present. Items within the qtreeview does subscribe to the data stream, so could be affected...
To be clear many times the program will run flawlessly. I'm looking for pointers, patterns, things people have seen in their code that could cause carnage that was not immediately obvious.
Cheers all
-
Did you check for memory consumption ?
Even if using Python there might be issues on that side.
From what you wrote, you seem to be mixing widgets and model views and possibly quite a lot of them. Are you using cellWidget ? (if so, don't it's not designed to handle big amounts of widgets).
Are you doing many allocation and deletion ?
If so, did you consider reuse of widgets ? -
wrote on 2 Aug 2022, 13:49 last edited by
Is this maybe a clash between the Qt libraries used by PySide6 and PyQtgraph?
-
wrote on 3 Aug 2022, 18:22 last edited by
thanks for the ideas guys. We still have no traction. I can say that the app will exit with very few widgets on screen, apart from one very large treeview. can I ask, with regards to widget addition, parenting and removal, are there any hard and fast no-no's? I not that some widgets are created without a parent, they are then added to layouts and then have their parent set. sometimes a a parent is set prior to layout. is it possible to make mistakes here? and some widgets can be closed programmatically by a call to their close() method. there will be many that are assumed to have gone away due to garbage collection (widgets that live inside the larger "closeable" widgets. is it possible to ,make a bad assumption here?
Thanks again
-
TreeView ? Are you using cell widgets ?
-
wrote on 6 Aug 2022, 02:42 last edited by
@SGaist hmm. yes we have a QTreeView, and no cell widgets. the internet had not poined me that way - being so green Ive relied on examples from the internet. the treeview is populated with QStandardItem's.... is that a problem? heres how we start with that particular part of the program.
self.treeview = QTreeView() self.treeview.setHeaderHidden(True) self.model = QStandardItemModel() self.treeview.setModel(self.model) self.create_nodes(tree_data, self.model) ...
from there, its a case of adding a bunch of QStandardItem()'s. sounds plausible? or maybe not?
-
wrote on 6 Aug 2022, 08:26 last edited by
alright. ive worked through all the little issues that come with rolling back to qt5 - the progarm is more stable - but many small regressions ill have to work through due to small incompatibilities between the v5 and v6 API's. Im done - thanks for the suggestions guys.
-
So no, you were doing nothing wrong from what it seems.
You may have an application that is pushing the bindings.
What regressions are you encountering ?
-
So no, you were doing nothing wrong from what it seems.
You may have an application that is pushing the bindings.
What regressions are you encountering ?
wrote on 6 Aug 2022, 21:12 last edited by@SGaist Ive spent a day (and some night xD) working through, and I feel confident that Ive found and understood every issue so far encountered.
I can tell you that there were in fact very few issues.
2 points ill share, and please correct me if I describe them incorrectly - im only acting as an observer and have no clue about the internals of the bindings:- pyqt5 seems more strictly typed than PySide6. examples of changes:
#Pyside6 QColorDialog.setCustomColor(i, "#ffffff") QWidget.move(x, y) QWebEngineView.setUrl(url) #PyQt5 # my program previously used a basic color string throughout - now I need to use QColor - not a problem and is forward compatible QColorDialog.setCustomColor(i, QColor("#ffffff")) # my program was not distinuishing floats from ints, in some places. the source of data for move() is not controllable in that way so, ive cast to int. QWidget.move(int(x), int(y)) # similar like QColorDialog.setCustomColor QWebEngineView.setUrl(QUrl(url))
Ive made similar small changes in a few places, i could list all but I feel its not difficult because Im only seeing problems because this was never a qt5 app. all changes look forward compatible to me.
- the stranger thing, which worried me alot at the beginning, was the way Widgets and Layouts resolve to boolean. my code had a few lazy spots like this.
# works in PySide6, but turns out, in PyQt5 bool(self.my_layout) can be False even if self.my_layout has been made. Ive seeen the same with QTabWidget as well! # for today I assume that the original implementation was being clever. perhaps an empty widget/layout -> False, and a populated one -> True. # i was working on an assumption! if self.my_layout: self.my_layout.addWidget(mywidget) # PyQt5, ive corrected to: if self.my_layout is not None: self.my_layout.addWidget(mywidget)
and with a more specific method of checking if my items are present or not, the whole app works 99.999% the same as before, except with no crashes so far.
So, I can say that for my app, and my codebase, and for me, PySide6 has a far more Pythonic interface. once it stabilizes, Ill be pretty happy to roll forward. I wont be doing that any time soon though, for the following reasons:
- PySide6 has never been "silent crash" free for me and I have lost a lot of hair trying to get my product to release. how will I know when it has become amazing? well no one will be able to tell me, Id have to try it and this will cost me time!
- I physically cant try PySide6 - currently I use fbs (great package) and qtpy (also great) and PyQtGraph (also relies on qtpy, i believe) and these both currently crash because of namespace changes from 6.2.3 -> 6.3.x. now this, was a royal pain in the backside.
overall I am ready to go to release candidate now, and I couldnt be more pleased. Qt is a cool system once learned.
Thanks for helping and do feel free to correct my assumptions if Ive told it wrong.
-
So no, you were doing nothing wrong from what it seems.
You may have an application that is pushing the bindings.
What regressions are you encountering ?