PySide Bugzilla Closed for New Bugs

PySide is now a Qt Add-on and uses the Qt Project's JIRA Bug Tracker instead of this Bugzilla instance. This Bugzilla is left for reference purposes.

Bug 522 - example/threads/mandelbrot.py crashes on exit
: example/threads/mandelbrot.py crashes on exit
Status: CLOSED FIXED
Product: PySide
Classification: Unclassified
Component: Examples
: 1.0.0 beta1
: All All
: P3 normal
Assigned To: Hugo Parente Lima
:
:
:
  Show dependency treegraph
 
Reported: 2010-12-02 20:14 EET by Farsmo
Modified: 2011-01-21 15:44 EET (History)
8 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Farsmo 2010-12-02 20:14:02 EET
example/threads/mandelbrot.py crashes on exit with the message:

> QThread: Destroyed while thread is still running
> Error in sys.excepthook:
> 
> Original exception was:
>
Comment 1 Matti Airas 2010-12-03 04:43:49 EET
Thanks for the report! However, this is a duplicate of bug 504.

*** This bug has been marked as a duplicate of bug 504 ***
Comment 2 Hugo Parente Lima 2010-12-20 11:26:12 EET
Closign bugs after release of 1.0.0 beta2.
Comment 3 Matti Airas 2011-01-19 13:58:45 EET
(commenting to a comment on bug 504)

Indeed, this is not a duplicate. Marking it such was an oversight on my part --
sorry for the confusion.

Since this bug isn't properly resolved after all, I'm reopening it. However, if
the behaviour is identical in the C++ example, it's really an upstream issue
and there's not much we could/should do about it.
Comment 4 Hugo Parente Lima 2011-01-19 14:12:54 EET
The bug in the example code, not in the bindings and it's not really a bug it's
just a unellegant exit :-)
Comment 5 Matti Airas 2011-01-19 14:22:18 EET
Hugo, what about the issue of reopening windows? That at least makes the exit
mighty inelegant. :-)

I'd say we could still fix the example: they should be of a good quality, in
any case. I'm prioritizing this P4, though, as not to block more urgent things.
Comment 6 Farsmo 2011-01-19 14:30:53 EET
As I said in bug 504:

On my system I don't have any QThread problem with the C++ version, with MinGW
and Visual Studio (I didn't recompile the VS example with the 'console' flag: I
used the precompiled binary and set QT_FATAL_WARNINGS, but it exited with no
error).


The destructor ends with a QThread::wait() call, so the worst thing that should
happen is that the program could lock up, but the QThread can never be
destroyed until it has stopped running:

RenderThread::~RenderThread()
{
    mutex.lock();
    abort = true;
    condition.wakeOne();
    mutex.unlock();

    wait();
}


Matti also has a good point: it's not the first time that I get that reopening
window behavior on bugs instead of a clean crash like C++, so it might be worth
investigating.
Comment 7 Farsmo 2011-01-19 14:33:40 EET
QThread.__del__ simply doesn't get called, in fact:

from PySide.QtCore import *
from PySide.QtGui import *

class Thread(QThread):
    def __del__(self):
        print "deleting..."
        while True:
            pass
    def run(self):
        print "running..."
        while True:
            pass
        print "should not happen"

app = QApplication([])
w = QLabel("hello")
w.show()
t = Thread()
t.start()
app.exec_()


I'm really curious how you could have encountered a similar bug with the C++
version, Hugo?
Comment 8 Hugo Parente Lima 2011-01-19 14:38:45 EET
I fixed the example on my machine, but I can't push it to gitorious.. why?
simple, gitorious is a crap and doesn't work.

So when (if) gitorious back to normal I'll do the merge request to make this
warning disapear.
Comment 9 Hugo Parente Lima 2011-01-19 14:41:30 EET
(In reply to comment #7)
> QThread.__del__ simply doesn't get called, in fact:

It gets called, but after the sys.exit call because the window have a ref to
the self.thread object, this is why the thread don't die.

the fix is on:

http://qt.gitorious.org/pyside/pyside-examples/merge_requests/25

> from PySide.QtCore import *
> from PySide.QtGui import *
> 
> class Thread(QThread):
>     def __del__(self):
>         print "deleting..."
>         while True:
>             pass
>     def run(self):
>         print "running..."
>         while True:
>             pass
>         print "should not happen"
> 
> app = QApplication([])
> w = QLabel("hello")
> w.show()
> t = Thread()
> t.start()
> app.exec_()
> 
> 
> I'm really curious how you could have encountered a similar bug with the C++
> version, Hugo?
Comment 10 Hugo Parente Lima 2011-01-19 15:03:25 EET
I just checked this... I just don't know why PyQt doesn't show the warning,
because the run method never returns and the __del__ method is never called.
Probably the thread object is never destroyed.

The problem with the Python code is that it rely on the object destruction
order, but Python don't have a deterministic one as C++ have, this is why the
C++ code works without warning and the Python one not.
Comment 11 Hugo Parente Lima 2011-01-19 15:08:01 EET
I pushed the fix to the example on commit:

pyside-examples/777286a47cbee3439e439bb2cfa26bd5262c519c

Plz, check it.

I'll mark the bug as fixed as this remaining problem was not related to the bug
itself and was fixed anyway.
Comment 12 Hugo Parente Lima 2011-01-19 15:11:04 EET
Ah, btw my mistake, the example works fine on C++, sorry, I got confused.
Comment 13 Farsmo 2011-01-19 20:25:37 EET
(In reply to comment #11)
> I pushed the fix to the example on commit:
> 
> pyside-examples/777286a47cbee3439e439bb2cfa26bd5262c519c
> 
> Plz, check it.

Yes it works fine.

I don't really like removing the mutex as it relies on the existence of a GIL
(CPython itself hopes to remove it at some point). A simple renaming of __del__
could do the job just as well:

--- a/mandelbrot.py
+++ b/mandelbrot.py
@@ -56,7 +56,7 @@
         for i in range(RenderThread.ColormapSize):
             self.colormap.append(self.rgbFromWaveLength(380.0 + (i * 400.0 /
RenderThread.ColormapSize)))

-    def __del__(self):
+    def stop(self):
         self.mutex.lock()
         self.abort = True
         self.condition.wakeOne()
@@ -315,4 +315,6 @@
     app = QtGui.QApplication(sys.argv)
     widget = MandelbrotWidget()
     widget.show()
-    sys.exit(app.exec_())
+    res = app.exec_()
+    widget.thread.stop()
+    sys.exit(res)


(In reply to comment #10)
> The problem with the Python code is that it rely on the object destruction
> order, but Python don't have a deterministic one as C++ have, this is why the
> C++ code works without warning and the Python one not.

Not really: I don't think Python would delete a base class instance before it
deletes the derived class instance. So it should be possible for __del__ to be
called with the guarantee that the QThread hasn't been destroyed.
Comment 14 Farsmo 2011-01-19 20:40:57 EET
Actually I lied: I didn't test your actual commit, only my patch. I assume your
commit would fail when the thread is done computing because you don't do
self.condition.wakeOne().
Comment 15 Hugo Parente Lima 2011-01-20 13:31:35 EET
see reply on bug 505
Comment 16 renato filho 2011-01-21 15:44:40 EET
release beta4