0

This is my first foray into threading, so apologies for any obvious mistakes.

I have a PyQt widget, from which a new process, prog, is run in a different thread. In my main thread, I'm also redirecting stdout to a read-only QTextEdit. However, I get errors referring to recursion, and I'm worried that my threads are interfering in each other in a way which causes a print statement to go into an infinite loop. I only get these errors if I run prog from the GUI, and not from the command line. My stdout redirect is using the code in this SO answer

In pseudo-code, this is basically what I've got:

gui.py

class widget(QWidget):
  def __init__(self):
    self.button = QPushButton("GO!", self)
    self.button.clicked.connect(self.start)

  def start(self):
    self.thread = TaskThread()
    sys.stdout = EmittingStream(textWritten = self.outputText)
    self.thread.start()

  def outputText(self):
    #as in answer provided in link (EmittingStream in separate module)

prog.py

class TaskThread(QThread):
  def run(self):
    '''
      Long complicated program; putting in simpler code here (e.g. loop printing to 10000) doesn't reproduce errors 
    '''
  • Is there any way of finding out if my recursion is caused by an infinite loop, or by anything else?
  • Is my code obviously thread-unsafe?
  • How do you make functions guaranteed to be threadsafe? (Links to tutorials / books will be good!)
Community
  • 1
  • 1
ChrisW
  • 4,970
  • 7
  • 55
  • 92

3 Answers3

0

I can see you have located where the error is. But without the code there is not much that I can tell.

Filling your needs of direction, I'll point to you to Python profiles. Since it looks like you need some python profiling tools.

http://docs.python.org/2/library/profile.html

and a answer about the subject

How can you profile a Python script?

Community
  • 1
  • 1
Raydel Miranda
  • 13,825
  • 3
  • 38
  • 60
0

This is tricky, but I think that your code is thread-unsafe. Specifically, looking at other stackoverflow answers (here and here) it appears that you should not be accessing a Qt GUI object from another thread than the one it was created in (even a QThread).

Since any call to print in your code now accesses a Qt GUI object, it seems this is very thread unsafe.

My suggestion to make it safe would be to:

  1. Have a QThread, inside of which you have instantiated the output box (it is thread safe to access a Qt GUI object from the thread it was created in, and it does not have to be created in the main thread) Qt GUI objects are not reentrant and must be created and used in the main thread only, see here As such you will need a QThread to post events back to the main thread (using the Qt signals/slots mechanism which can be thread safe when done correctly)
  2. Have this QThread blocking on reading from a Python Queue. When it gets something from the queue, it places it in the Qt text box posts it back to the main thread, and the main thread will update the output box.
  3. Modify your EmmittingStream to place things in the Queue, rather than directly into the Qt output box.
Community
  • 1
  • 1
three_pineapples
  • 11,579
  • 5
  • 38
  • 75
  • My initial idea was wrong, if you want to be thread safe you need to post events from QThreads back to the main thread using either QApplication.postEvent() (fine in PyQt, leaks memory in PySide) or use the inbuilt signals/slots mechanism of QThreads and connect a slot from the main thread to a signal in the QThread (this connection must be made from the main thread or the __init__ method of your QThread) (the latter signal/slot option does not leak memory in PySide) Apologies for the mistake – three_pineapples Dec 11 '13 at 11:15
0

In a Qt application you must use one single thread to handle the all the gui part. You can use other threads for computations, but not for user interface.

Just post messages about updates in a queue in the worker threads and use the main thread to pick up those messages and update the GUI.

6502
  • 112,025
  • 15
  • 165
  • 265
  • Sorry, perhaps I didn't explain myself well enough. As far as I understand, I do have my GUI part in 1 thread and the computation part in a different thread. Your second paragraph, unfortunately, has gone right over my head. I'd better go off and read a book! – ChrisW Dec 16 '13 at 17:18