Application sometimes crashes, other times it performs a task incorrectly - think it's a Multithreading issue
-
Hi,
Apologies the code is in Python.
I have an application that has a GUI thread and many different worker threads. In this application, I have a functions.py module, which contains a lot of different "utility" functions that are used all over the application.
Yesterday the application has been released and some users (a minority, but still) has reported problems with the application crashing. I looked over my code and noticed a possible design flaw, and would like to check with the lovely people of SO and see if I am right and if this is indeed a flaw.
Suppose I have this defined in my functions.py module:
@class Functions:
solveComputationSignal = Signal(str) updateStatusSignal = Signal(int, str) text = None classmethod def setResultText(self, text): self.text = text classmethod def solveComputation(cls, platform, computation, param=None): #Not the entirety of the method is listed here result = urllib.urlopen(COMPUTATION_URL).read() if param is None: cls.solveComputationSignal.emit(result) else: cls.solveAlternateComputation(platform, computation) while not self.text: time.sleep(3) return self.text if self.text else False classmethod def updateCurrentStatus(cls, platform, statusText): cls.updateStatusSignal.emit(platform, statusText)@
I think these methods in themselves are fine. The two signals defined here are connected to in the GUI thread. The first signal pops-up a dialog in which the computation is presented. The GUI thread calls the setResultText() method and sets the resulting string as entered by the user (if anyone knows of a better way to wait until the user has inputted the text other than sleeping and waiting for self.text to become True, please let me know). The solveAlternateComputation is another method in the same class that solves the computation automatically, however, it too calls the setResultText() method that sets the resulting text.
The second signal updates the statusBar text of the main GUI as well.
What's worse is that I think the above design, while perhaps flawed, is not the problem.
The problem lies, I believe, in the way I call these methods, whihch is from the worker threads (note that I have multiple similar workers, all of which are different "platforms")
Assume I have this (and I do):
@class WorkerPlatform1(QThread):
#Init and other methods are here def run(self): #Thread does its job here, but then when it needs to present the #computation, instead of emitting a signal, this is what I do self.f = functions.Functions result = self.f.solveComputation(platform, computation) if result: #Go on with the task else: self.f.updateCurrentStatus(platform, "Error grabbing computation!")@
In this case I think that my flaw is that the thread itself is not emitting any signals, but rather calling callables residing outside of that thread directly. Am I right in thinking that this could cause my application to crash? Although the faulty module is reported as QtGui4.dll
One more thing: both of these methods in the Functions class are accessed by many threads almost simultaneously. Is this even advisable - have methods residing outside of a thread be accessed by many threads all at the same time? Can it so happen that I "confuse" my program? The reason I am asking is because people who say that the application is not crashing report that, very often, the solveComputation() returns the incorrect text - not all the time, but very often. Since that COMPUTATION_URL's server can take some time to respond (even 10+ seconds), is it possible that, once a thread calls that method, while the urllib library is still waiting for server response, in that time another thread can call it, causing it to use a different COMPUTATION_URL, which will result in it returning an incorrect value on some cases?
Finally, I am thinking of solutions: for my first (crashing) problem, do you think the proper solution would be to directly emit a Signal from the thread itself, and then connect it in the GUI thread? Is that the right way to go about it?
Secondly, for the solveComputation returning incorrect values, would I solve it by moving that method (and accompanying methods) to every Worker class? then I could call them directly and hopefully have the correct response - or, dozens of different responses (since I have that many threads) - for every thread?
Thank you all and I apologize for the wall of text.
EDIT: I would like to add that when running in console with some users, this error appears @QObject: Cannot create children for a parent that is in a different thread. (Parent is QLabel(0x4795500), parent's thread is QThread(0x2d3fd90), current thread is WordpressCreator(0x49f0548)@