PDA

View Full Version : Application sometimes crashes, other times does a task incorrectly (Multithreading)



Deusdies
2nd December 2012, 22:38
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)

amleto
3rd December 2012, 10:25
Hi,

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.


and what about us? :p

(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 obvious way is to use a QDialog...

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?
Yes.

both of these methods in the Functions class are accessed by many threads almost simultaneously. Is this even advisable
If there is only one Functions instance per thread, then it is ok. If you are sharing the instance, then no. Since these are classmethods then it is not thread safe.

E.G
there should be no need for


while not self.text:
time.sleep(3)

return self.text if self.text else False # If you really need this x if x else y, then you are using this method with threads in a non-thread safe way.
# The 'while not self.text' should guarantee that self.text is not empty/null. If it is not, then you must have another thread that is somehow interfering.


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?
Yes.

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?
Perhaps that will work. It is not a good solution, though - make you Functions methods into instance methods, and use one Functions instance per thread.


oh, and since you neglected to do so, here is the SO thread that your also started:
http://stackoverflow.com/questions/13674322/a-couple-of-questions-about-calling-methods-outside-of-qthread-from-within-the-q