<div dir="ltr"><div class="markdown-here-wrapper" style><p style="margin:1.2em 0px!important">All,</p>
<p style="margin:1.2em 0px!important">I think I’ve answered my own question. The basic assumption: <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;display:inline;background-color:rgb(248,248,248)">parent.destroyed()</code> will be emitted shortly before a class’ C++ destructor would be invoked. For Python cleanup, simply connect a method to this slot and perform cleanup. Does that seem reasonable? Also, does everyone agree with comments in the code (using <code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;display:inline;background-color:rgb(248,248,248)">deleteLater()</code> to destroy the Worker, then setting it to None, for example)?</p>
<p style="margin:1.2em 0px!important">Thanks for any insight or input.</p>
<p style="margin:1.2em 0px!important">Bryan</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;display:inline;background-color:rgb(248,248,248);white-space:pre;overflow:auto;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important"># Test program to ask about destructors and PyQt4.
import sys, time
from PyQt4.QtGui import QApplication
from PyQt4.QtCore import QThread, QTimer, QObject, pyqtSignal
# A Worker that does nothing but wait as its computational task.
class Worker(QObject):
def onStartWork(self):
time.sleep(2)
class ThreadController(QObject):
startWork = pyqtSignal()
def __init__(self, parent):
QObject.__init__(self, parent)
# No parent object provided; if so, we get the error
# "QObject::moveToThread: Cannot move objects with a parent".
# Likewise, calling setParent after moving the object produces
# "QObject::setParent: Cannot set parent, new parent is in a different
# thread". So, we must manually invoke this object's destructor in
# self.onParentDestroyed.
self.worker = Worker()
self.workerThread = QThread(self)
self.worker.moveToThread(self.workerThread)
# Since there's no way to invoke a method when the C++ destructor of
# this class is called, approximate it by looking for the destroyed()
# signal of the parent -- this object will soon have its destructor
# invoked by the parent.
parent.destroyed.connect(self.onParentDestroyed)
self.startWork.connect(self.worker.onStartWork)
self.workerThread.start()
self.startWork.emit()
# This is run shortly before this class's C++ destructor is invoked. It
# emulates a C++ destructor by freeing resourced before the C++ class is
# destroyed. Without this, we get nasty crashes since the Python portion
# of the class is still alive. At a minimum, we see "QThread: Destroyed
# while thread is still running" messages.
def onParentDestroyed(self):
print('onParentDestroyed')
# Use deleteLater() to allow the worker to finish up any events in its
# queue, then have its destructor invoked. Remove this class' reference
# to it, allowing Python to garbage collect the Python half of the class
# when the C++ part is deleted by deleteLater().
self.worker.deleteLater()
self.worker = None
# Now, shut down the thread the Worker runs in.
self.workerThread.quit()
self.workerThread.wait()
# Finally, detach (and probably garbage collect) the remaining object
# used by this class.
self.workerThread = None
if __name__ == '__main__':
app = QApplication(sys.argv)
# Exit the program shortly after the event loop starts up, but before the
# thread finishes.
QTimer.singleShot(500, app.exit)
# Start a thread
tm = ThreadController(app)
# Run the main event loop.
sys.exit(app.exec_())
</code></pre><div title="MDH:QWxsLDxkaXY+PGJyPjwvZGl2PjxkaXY+SSB0aGluayBJJ3ZlIGFuc3dlcmVkIG15IG93biBxdWVz
dGlvbi4gVGhlIGJhc2ljIGFzc3VtcHRpb246IGBgcGFyZW50LmRlc3Ryb3llZCgpYGAgd2lsbCBi
ZSBlbWl0dGVkIHNob3J0bHkgYmVmb3JlIGEgY2xhc3MnIEMrKyBkZXN0cnVjdG9yIHdvdWxkIGJl
IGludm9rZWQuIEZvciBQeXRob24gY2xlYW51cCwgc2ltcGx5IGNvbm5lY3QgYSBtZXRob2QgdG8g
dGhpcyBzbG90IGFuZCBwZXJmb3JtIGNsZWFudXAuIERvZXMgdGhhdCBzZWVtIHJlYXNvbmFibGU/
IEFsc28sIGRvZXMgZXZlcnlvbmUgYWdyZWUgd2l0aCBjb21tZW50cyBpbiB0aGUgY29kZSAodXNp
bmcgYGBkZWxldGVMYXRlcigpYGAgdG8gZGVzdHJveSB0aGUgV29ya2VyLCB0aGVuIHNldHRpbmcg
aXQgdG8gTm9uZSwgZm9yIGV4YW1wbGUpPzwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+VGhhbmtz
IGZvciBhbnkgaW5zaWdodCBvciBpbnB1dC48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PkJyeWFu
PC9kaXY+PGRpdj48YnI+PC9kaXY+PGRpdj48ZGl2PiZuYnNwOyAmbmJzcDsgIyBUZXN0IHByb2dy
YW0gdG8gYXNrIGFib3V0IGRlc3RydWN0b3JzIGFuZCBQeVF0NC48L2Rpdj48ZGl2PiZuYnNwOyAm
bmJzcDsmbmJzcDs8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgaW1wb3J0IHN5cywgdGltZTwvZGl2
PjxkaXY+Jm5ic3A7ICZuYnNwOyBmcm9tIFB5UXQ0LlF0R3VpIGltcG9ydCBRQXBwbGljYXRpb248
L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgZnJvbSBQeVF0NC5RdENvcmUgaW1wb3J0IFFUaHJlYWQs
IFFUaW1lciwgUU9iamVjdCwgcHlxdFNpZ25hbDwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyZuYnNw
OzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAjIEEgV29ya2VyIHRoYXQgZG9lcyBub3RoaW5nIGJ1
dCB3YWl0IGFzIGl0cyBjb21wdXRhdGlvbmFsIHRhc2suPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7
IGNsYXNzIFdvcmtlcihRT2JqZWN0KTo8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZu
YnNwOyBkZWYgb25TdGFydFdvcmsoc2VsZik6PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyB0aW1lLnNsZWVwKDIpPC9kaXY+PGRpdj4mbmJzcDsgJm5i
c3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7IGNsYXNzIFRocmVhZENvbnRyb2xsZXIo
UU9iamVjdCk6PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgc3RhcnRXb3Jr
ID0gcHlxdFNpZ25hbCgpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgZGVm
IF9faW5pdF9fKHNlbGYsIHBhcmVudCk6PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyBRT2JqZWN0Ll9faW5pdF9fKHNlbGYsIHBhcmVudCk8L2Rpdj48
ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgTm8gcGFyZW50
IG9iamVjdCBwcm92aWRlZDsgaWYgc28sIHdlIGdldCB0aGUgZXJyb3I8L2Rpdj48ZGl2PiZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgIlFPYmplY3Q6Om1vdmVUb1Ro
cmVhZDogQ2Fubm90IG1vdmUgb2JqZWN0cyB3aXRoIGEgcGFyZW50Ii48L2Rpdj48ZGl2PiZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgTGlrZXdpc2UsIGNhbGxpbmcg
c2V0UGFyZW50IGFmdGVyIG1vdmluZyB0aGUgb2JqZWN0IHByb2R1Y2VzPC9kaXY+PGRpdj4mbmJz
cDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICJRT2JqZWN0OjpzZXRQYXJl
bnQ6IENhbm5vdCBzZXQgcGFyZW50LCBuZXcgcGFyZW50IGlzIGluIGEgZGlmZmVyZW50PC9kaXY+
PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIHRocmVhZCIu
IFNvLCB3ZSBtdXN0IG1hbnVhbGx5IGludm9rZSB0aGlzIG9iamVjdCdzIGRlc3RydWN0b3IgaW48
L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgc2Vs
Zi5vblBhcmVudERlc3Ryb3llZC48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyAmbmJzcDsgJm5ic3A7IHNlbGYud29ya2VyID0gV29ya2VyKCk8L2Rpdj48ZGl2PiZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IHNlbGYud29ya2VyVGhyZWFkID0gUVRo
cmVhZChzZWxmKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgc2VsZi53b3JrZXIubW92ZVRvVGhyZWFkKHNlbGYud29ya2VyVGhyZWFkKTwvZGl2Pjxk
aXY+Jm5ic3A7ICZuYnNwOyZuYnNwOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgIyBTaW5jZSB0aGVyZSdzIG5vIHdheSB0byBpbnZva2UgYSBtZXRo
b2Qgd2hlbiB0aGUgQysrIGRlc3RydWN0b3Igb2Y8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgdGhpcyBjbGFzcyBpcyBjYWxsZWQsIGFwcHJveGlt
YXRlIGl0IGJ5IGxvb2tpbmcgZm9yIHRoZSBkZXN0cm95ZWQoKTwvZGl2PjxkaXY+Jm5ic3A7ICZu
YnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBzaWduYWwgb2YgdGhlIHBhcmVudCAt
LSB0aGlzIG9iamVjdCB3aWxsIHNvb24gaGF2ZSBpdHMgZGVzdHJ1Y3RvcjwvZGl2PjxkaXY+Jm5i
c3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBpbnZva2VkIGJ5IHRoZSBw
YXJlbnQuPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyBwYXJlbnQuZGVzdHJveWVkLmNvbm5lY3Qoc2VsZi5vblBhcmVudERlc3Ryb3llZCk8L2Rpdj48
ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IHNlbGYuc3RhcnRX
b3JrLmNvbm5lY3Qoc2VsZi53b3JrZXIub25TdGFydFdvcmspPC9kaXY+PGRpdj4mbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBzZWxmLndvcmtlclRocmVhZC5zdGFydCgp
PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBzZWxm
LnN0YXJ0V29yay5lbWl0KCk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsmbmJzcDs8L2Rpdj48ZGl2
PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIFRoaXMgaXMgcnVuIHNob3J0bHkgYmVmb3Jl
IHRoaXMgY2xhc3MncyBDKysgZGVzdHJ1Y3RvciBpcyBpbnZva2VkLiBJdDwvZGl2PjxkaXY+Jm5i
c3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgZW11bGF0ZXMgYSBDKysgZGVzdHJ1Y3RvciBieSBm
cmVlaW5nIHJlc291cmNlZCBiZWZvcmUgdGhlIEMrKyBjbGFzcyBpczwvZGl2PjxkaXY+Jm5ic3A7
ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgZGVzdHJveWVkLiBXaXRob3V0IHRoaXMsIHdlIGdldCBu
YXN0eSBjcmFzaGVzIHNpbmNlIHRoZSBQeXRob24gcG9ydGlvbjwvZGl2PjxkaXY+Jm5ic3A7ICZu
YnNwOyAmbmJzcDsgJm5ic3A7ICMgb2YgdGhlIGNsYXNzIGlzIHN0aWxsIGFsaXZlLiBBdCBhIG1p
bmltdW0sIHdlIHNlZSAiUVRocmVhZDogRGVzdHJveWVkPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7
ICZuYnNwOyAmbmJzcDsgIyB3aGlsZSB0aHJlYWQgaXMgc3RpbGwgcnVubmluZyIgbWVzc2FnZXMu
PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgZGVmIG9uUGFyZW50RGVzdHJv
eWVkKHNlbGYpOjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgcHJpbnQoJ29uUGFyZW50RGVzdHJveWVkJyk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgVXNlIGRlbGV0ZUxhdGVyKCkgdG8gYWxsb3cg
dGhlIHdvcmtlciB0byBmaW5pc2ggdXAgYW55IGV2ZW50cyBpbiBpdHM8L2Rpdj48ZGl2PiZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgcXVldWUsIHRoZW4gaGF2ZSBp
dHMgZGVzdHJ1Y3RvciBpbnZva2VkLiBSZW1vdmUgdGhpcyBjbGFzcycgcmVmZXJlbmNlPC9kaXY+
PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIHRvIGl0LCBh
bGxvd2luZyBQeXRob24gdG8gZ2FyYmFnZSBjb2xsZWN0IHRoZSBQeXRob24gaGFsZiBvZiB0aGUg
Y2xhc3M8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7
ICMgd2hlbiB0aGUgQysrIHBhcnQgaXMgZGVsZXRlZCBieSBkZWxldGVMYXRlcigpLjwvZGl2Pjxk
aXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgc2VsZi53b3JrZXIu
ZGVsZXRlTGF0ZXIoKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyAmbmJzcDsgc2VsZi53b3JrZXIgPSBOb25lPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIE5vdywgc2h1dCBkb3duIHRoZSB0aHJlYWQgdGhlIFdv
cmtlciBydW5zIGluLjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyAmbmJzcDsgc2VsZi53b3JrZXJUaHJlYWQucXVpdCgpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7
ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBzZWxmLndvcmtlclRocmVhZC53YWl0KCk8L2Rp
dj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgRmluYWxs
eSwgZGV0YWNoIChhbmQgcHJvYmFibHkgZ2FyYmFnZSBjb2xsZWN0KSB0aGUgcmVtYWluaW5nIG9i
amVjdDwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsg
IyB1c2VkIGJ5IHRoaXMgY2xhc3MuPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJz
cDsgJm5ic3A7ICZuYnNwOyBzZWxmLndvcmtlclRocmVhZCA9IE5vbmU8L2Rpdj48ZGl2PiZuYnNw
OyAmbmJzcDsmbmJzcDs8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgaWYgX19uYW1lX18gPT0gJ19f
bWFpbl9fJzo8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBhcHAgPSBRQXBw
bGljYXRpb24oc3lzLmFyZ3YpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9kaXY+PGRp
dj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBFeGl0IHRoZSBwcm9ncmFtIHNob3J0bHkg
YWZ0ZXIgdGhlIGV2ZW50IGxvb3Agc3RhcnRzIHVwLCBidXQgYmVmb3JlIHRoZTwvZGl2PjxkaXY+
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgdGhyZWFkIGZpbmlzaGVzLjwvZGl2PjxkaXY+
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IFFUaW1lci5zaW5nbGVTaG90KDUwMCwgYXBwLmV4
aXQpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7
ICZuYnNwOyAmbmJzcDsgIyBTdGFydCBhIHRocmVhZDwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7IHRtID0gVGhyZWFkQ29udHJvbGxlcihhcHApPC9kaXY+PGRpdj4mbmJzcDsg
Jm5ic3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBSdW4g
dGhlIG1haW4gZXZlbnQgbG9vcC48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyBzeXMuZXhpdChhcHAuZXhlY18oKSk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsmbmJzcDs8L2Rp
dj48L2Rpdj4=" style="height:0;font-size:0em;padding:0;margin:0"></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Nov 3, 2014 at 4:07 PM, Jones, Bryan <span dir="ltr"><<a href="mailto:bjones@ece.msstate.edu" target="_blank">bjones@ece.msstate.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>
<div dir="ltr">
<div><span class="">
<p style="margin:1.2em 0px!important">All,</p>
<p style="margin:1.2em 0px!important">Pardon the double post. I saw a few obvious bugs after hitting send. My apologies. Here is the improved version.</p>
</span><p style="margin:1.2em 0px!important">Bryan</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;display:inline;background-color:rgb(248,248,248);white-space:pre-wrap;overflow:auto;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important"># Test program to ask about destructors and PyQt4.
import sys, time
from PyQt4.QtGui import QApplication
from PyQt4.QtCore import QThread, QTimer, QObject, pyqtSignal
class Worker(QObject):
def onStartWork(self):
time.sleep(1)
class ThreadController(QObject):
startWork = pyqtSignal()
def __init__(self, parent):
QObject.__init__(self, parent)
# No parent object provided; if so, we get the error
# "QObject::moveToThread: Cannot move objects with a parent".
# Likewise, calling setParent after moving the object produces
# "QObject::setParent: Cannot set parent, new parent is in a different
# thread". Who will deallocate this object, since it has no parent? I
# assume the answer is "Python, maybe". Is that good enough?
self.worker = Worker()
self.workerThread = QThread(self)
self.worker.moveToThread(self.workerThread)
# Use method #2 below. Commnet out for an ominous warning which will
# crash in a more complex program: "QThread: Destroyed while thread is
# still running".
#parent.aboutToQuit.connect(self.del_)
self.startWork.connect(self.worker.onStartWork)
self.workerThread.start()
# I'd like to run when when ~ThreadController is invoked. That's quite
# differentfrom when __del__ is invoked. How?
#
# 1. Give up. Just invoke it manually. However, this is error-prone (i.e.
# I'll forget to do it at some point).
# 2. Connect app.aboutToQuit to this. This seems fairly reasonable, but
# it would feel cleaner to invoke when the destructor is invoked,
# rather than earlier. Also, this means that the QApplication would
# need to be passed to every thread, which might involve awkwardness
# in passing it through several intervening subclasses.
# 3. Connect destroyed(), which doesn't work -- this isn't emitted until
# the object is mostly dead, far after ~ThreadController was invoked,
# and won't be executed.
# 4. Have __del__ invoke this, which doesn't work -- it only happens after
# ~ThreadController has finihed.
def del_(self):
print('del_')
self.workerThread.quit()
self.workerThread.wait()
def __del__(self):
print('__del__')
# Crash when uncommented.
#self.del_()
if __name__ == '__main__':
app = QApplication(sys.argv)
# Exit the program shortly after the event loop starts up, but before the
# thread finishes.
QTimer.singleShot(200, app.exit)
# Start a thread
tm = ThreadController(app)
# Run the main event loop.
ret = app.exec_()
print('done')
sys.exit(ret)
</code></pre>
<div title="MDH:QWxsLDxkaXY+PGJyPjwvZGl2PjxkaXY+UGFyZG9uIHRoZSBkb3VibGUgcG9zdC4gSSBzYXcgYSBm
ZXcgb2J2aW91cyBidWdzIGFmdGVyIGhpdHRpbmcgc2VuZC4gTXkgYXBvbG9naWVzLiBIZXJlIGlz
IHRoZSBpbXByb3ZlZCB2ZXJzaW9uLjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+QnJ5YW48L2Rp
dj48ZGl2Pjxicj48L2Rpdj48ZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAjIFRlc3QgcHJvZ3JhbSB0
byBhc2sgYWJvdXQgZGVzdHJ1Y3RvcnMgYW5kIFB5UXQ0LjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNw
OyZuYnNwOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyBpbXBvcnQgc3lzLCB0aW1lPC9kaXY+PGRp
dj4mbmJzcDsgJm5ic3A7IGZyb20gUHlRdDQuUXRHdWkgaW1wb3J0IFFBcHBsaWNhdGlvbjwvZGl2
PjxkaXY+Jm5ic3A7ICZuYnNwOyBmcm9tIFB5UXQ0LlF0Q29yZSBpbXBvcnQgUVRocmVhZCwgUVRp
bWVyLCBRT2JqZWN0LCBweXF0U2lnbmFsPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9k
aXY+PGRpdj4mbmJzcDsgJm5ic3A7IGNsYXNzIFdvcmtlcihRT2JqZWN0KTo8L2Rpdj48ZGl2PiZu
YnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBkZWYgb25TdGFydFdvcmsoc2VsZik6PC9kaXY+PGRp
dj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyB0aW1lLnNsZWVwKDEp
PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7IGNs
YXNzIFRocmVhZENvbnRyb2xsZXIoUU9iamVjdCk6PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgc3RhcnRXb3JrID0gcHlxdFNpZ25hbCgpPC9kaXY+PGRpdj4mbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgZGVmIF9faW5pdF9fKHNlbGYsIHBhcmVudCk6PC9kaXY+PGRpdj4m
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBRT2JqZWN0Ll9faW5pdF9f
KHNlbGYsIHBhcmVudCk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJz
cDsgJm5ic3A7ICMgTm8gcGFyZW50IG9iamVjdCBwcm92aWRlZDsgaWYgc28sIHdlIGdldCB0aGUg
ZXJyb3I8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7
ICMgIlFPYmplY3Q6Om1vdmVUb1RocmVhZDogQ2Fubm90IG1vdmUgb2JqZWN0cyB3aXRoIGEgcGFy
ZW50Ii48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7
ICMgTGlrZXdpc2UsIGNhbGxpbmcgc2V0UGFyZW50IGFmdGVyIG1vdmluZyB0aGUgb2JqZWN0IHBy
b2R1Y2VzPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyAjICJRT2JqZWN0OjpzZXRQYXJlbnQ6IENhbm5vdCBzZXQgcGFyZW50LCBuZXcgcGFyZW50IGlz
IGluIGEgZGlmZmVyZW50PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7ICZuYnNwOyAjIHRocmVhZCIuIFdobyB3aWxsIGRlYWxsb2NhdGUgdGhpcyBvYmplY3QsIHNp
bmNlIGl0IGhhcyBubyBwYXJlbnQ/IEk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgJm5ic3A7ICMgYXNzdW1lIHRoZSBhbnN3ZXIgaXMgIlB5dGhvbiwgbWF5YmUi
LiBJcyB0aGF0IGdvb2QgZW5vdWdoPzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgc2VsZi53b3JrZXIgPSBXb3JrZXIoKTwvZGl2PjxkaXY+Jm5ic3A7
ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgc2VsZi53b3JrZXJUaHJlYWQgPSBR
VGhyZWFkKHNlbGYpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7
ICZuYnNwOyBzZWxmLndvcmtlci5tb3ZlVG9UaHJlYWQoc2VsZi53b3JrZXJUaHJlYWQpPC9kaXY+
PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAjIFVzZSBtZXRob2QgIzIgYmVsb3cuIENvbW1uZXQgb3V0IGZv
ciBhbiBvbWlub3VzIHdhcm5pbmcgd2hpY2ggd2lsbDwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBjcmFzaCBpbiBhIG1vcmUgY29tcGxleCBwcm9n
cmFtOiAiUVRocmVhZDogRGVzdHJveWVkIHdoaWxlIHRocmVhZCBpczwvZGl2PjxkaXY+Jm5ic3A7
ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBzdGlsbCBydW5uaW5nIi48L2Rp
dj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICNwYXJlbnQu
YWJvdXRUb1F1aXQuY29ubmVjdChzZWxmLmRlbF8pPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBzZWxmLnN0YXJ0V29yay5jb25uZWN0KHNlbGYud29y
a2VyLm9uU3RhcnRXb3JrKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgc2VsZi53b3JrZXJUaHJlYWQuc3RhcnQoKTwvZGl2PjxkaXY+Jm5ic3A7ICZu
YnNwOyZuYnNwOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgSSdkIGxp
a2UgdG8gcnVuIHdoZW4gd2hlbiB+VGhyZWFkQ29udHJvbGxlciBpcyBpbnZva2VkLiBUaGF0J3Mg
cXVpdGU8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIGRpZmZlcmVudGZy
b20gd2hlbiBfX2RlbF9fIGlzIGludm9rZWQuIEhvdz88L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyAjPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAx
LiBHaXZlIHVwLiBKdXN0IGludm9rZSBpdCBtYW51YWxseS4gSG93ZXZlciwgdGhpcyBpcyBlcnJv
ci1wcm9uZSAoaS5lLjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgJm5i
c3A7ICZuYnNwO0knbGwgZm9yZ2V0IHRvIGRvIGl0IGF0IHNvbWUgcG9pbnQpLjwvZGl2PjxkaXY+
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgMi4gQ29ubmVjdCBhcHAuYWJvdXRUb1F1aXQg
dG8gdGhpcy4gVGhpcyBzZWVtcyBmYWlybHkgcmVhc29uYWJsZSwgYnV0PC9kaXY+PGRpdj4mbmJz
cDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAmbmJzcDsgJm5ic3A7aXQgd291bGQgZmVlbCBjbGVh
bmVyIHRvIGludm9rZSB3aGVuIHRoZSBkZXN0cnVjdG9yIGlzIGludm9rZWQsPC9kaXY+PGRpdj4m
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAmbmJzcDsgJm5ic3A7cmF0aGVyIHRoYW4gZWFy
bGllci4gQWxzbywgdGhpcyBtZWFucyB0aGF0IHRoZSBRQXBwbGljYXRpb24gd291bGQ8L2Rpdj48
ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICZuYnNwOyAmbmJzcDtuZWVkIHRvIGJl
IHBhc3NlZCB0byBldmVyeSB0aHJlYWQsIHdoaWNoIG1pZ2h0IGludm9sdmUgYXdrd2FyZG5lc3M8
L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICZuYnNwOyAmbmJzcDtpbiBw
YXNzaW5nIGl0IHRocm91Z2ggc2V2ZXJhbCBpbnRlcnZlbmluZyBzdWJjbGFzc2VzLjwvZGl2Pjxk
aXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgMy4gQ29ubmVjdCBkZXN0cm95ZWQoKSwg
d2hpY2ggZG9lc24ndCB3b3JrIC0tIHRoaXMgaXNuJ3QgZW1pdHRlZCB1bnRpbDwvZGl2PjxkaXY+
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgJm5ic3A7ICZuYnNwO3RoZSBvYmplY3QgaXMg
bW9zdGx5IGRlYWQsIGZhciBhZnRlciB+VGhyZWFkQ29udHJvbGxlciB3YXMgaW52b2tlZCw8L2Rp
dj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICZuYnNwOyAmbmJzcDthbmQgd29u
J3QgYmUgZXhlY3V0ZWQuPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyA0
LiBIYXZlIF9fZGVsX18gaW52b2tlIHRoaXMsIHdoaWNoIGRvZXNuJ3Qgd29yayAtLSBpdCBvbmx5
IGhhcHBlbnMgYWZ0ZXI8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICZu
YnNwOyAmbmJzcDt+VGhyZWFkQ29udHJvbGxlciBoYXMgZmluaWhlZC48L2Rpdj48ZGl2PiZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBkZWYgZGVsXyhzZWxmKTo8L2Rpdj48ZGl2PiZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IHByaW50KCdkZWxfJyk8L2Rpdj48ZGl2
PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IHNlbGYud29ya2VyVGhy
ZWFkLnF1aXQoKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgc2VsZi53b3JrZXJUaHJlYWQud2FpdCgpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5i
c3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgZGVmIF9fZGVsX18oc2Vs
Zik6PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBw
cmludCgnX19kZWxfXycpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7ICZuYnNwOyAjIENyYXNoIHdoZW4gdW5jb21tZW50ZWQuPC9kaXY+PGRpdj4mbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjc2VsZi5kZWxfKCk8L2Rpdj48ZGl2PiZu
YnNwOyAmbmJzcDsmbmJzcDs8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgaWYgX19uYW1lX18gPT0g
J19fbWFpbl9fJzo8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBhcHAgPSBR
QXBwbGljYXRpb24oc3lzLmFyZ3YpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9kaXY+
PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBFeGl0IHRoZSBwcm9ncmFtIHNob3J0
bHkgYWZ0ZXIgdGhlIGV2ZW50IGxvb3Agc3RhcnRzIHVwLCBidXQgYmVmb3JlIHRoZTwvZGl2Pjxk
aXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgdGhyZWFkIGZpbmlzaGVzLjwvZGl2Pjxk
aXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IFFUaW1lci5zaW5nbGVTaG90KDIwMCwgYXBw
LmV4aXQpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgIyBTdGFydCBhIHRocmVhZDwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNw
OyAmbmJzcDsgJm5ic3A7IHRtID0gVGhyZWFkQ29udHJvbGxlcihhcHApPC9kaXY+PGRpdj4mbmJz
cDsgJm5ic3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBS
dW4gdGhlIG1haW4gZXZlbnQgbG9vcC48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZu
YnNwOyByZXQgPSBhcHAuZXhlY18oKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7IHByaW50KCdkb25lJyk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBz
eXMuZXhpdChyZXQpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7Jm5ic3A7PC9kaXY+PC9kaXY+" style="min-height:0;font-size:0em;padding:0;margin:0">
</div>
</div>
</div>
<div class="gmail_extra"><br>
<div class="gmail_quote"><span class="">On Mon, Nov 3, 2014 at 3:59 PM, Bryan A. Jones <span dir="ltr">
<<a href="mailto:bjones@ece.msstate.edu" target="_blank">bjones@ece.msstate.edu</a>></span> wrote:<br>
</span><div><div class="h5"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="ltr">
<div>
<p style="margin:1.2em 0px!important">All,</p>
<p style="margin:1.2em 0px!important">I’m confused when it comes to the proper way to mesh Qt’s model of creating a tree of parented objects which destroy themselves when no longer used with Python’s “delete it when I feel like it” garbage collector. In particular,
I’d like to shut down threads when the underlying Qt objects are destroyed, but I can’t figure out how to do that. Any advice and wisdom would be appreciated. I've attached same code with my thoughts.</p>
<p style="margin:1.2em 0px!important">Bryan</p>
<pre style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;padding:0px 0.3em;white-space:pre-wrap;border:1px solid rgb(234,234,234);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;display:inline;background-color:rgb(248,248,248);white-space:pre-wrap;overflow:auto;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;border:1px solid rgb(204,204,204);padding:0.5em 0.7em;display:block!important"># Test program to ask about destructors and PyQt4.
import sys, time
from PyQt4.QtGui import QApplication
from PyQt4.QtCore import QThread, QTimer, QObject
class Worker(QObject):
def run(self):
time.sleep(1)
class ThreadController(QObject):
def __init__(self, parent):
QObject.__init__(self, parent)
# No parent object provided; if so, we get the error
# "QObject::moveToThread: Cannot move objects with a parent".
# Who will deallocate this object, since it has no parent? I
# assume the answer is "Python, maybe". Is that good enough?
self.worker = Worker()
self.workerThread = QThread(self)
self.worker.moveToThread(self.workerThread)
# Use method #2 below. Commnet out for a crash.
parent.aboutToQuit.connect(self.del_)
self.workerThread.start()
# I'd like to run when when ~ThreadController is invoked. That's quite
# differentfrom when __del__ is invoked. How?
#
# 1. Give up. Just invoke it manually. However, this is error-prone (i.e.
# I'll forget to do it at some point).
# 2. Connect app.aboutToQuit to this. This seems fairly reasonable, but
# it would feel cleaner to invoke when the destructor is invoked,
# rather than earlier. Also, this means that the QApplication would
# need to be passed to every thread, which might involve awkwardness
# in passing it through several intervening subclasses.
# 3. Connect destroyed(), which doesn't work -- this isn't emitted until
# the object is mostly dead, far after ~ThreadController was invoked,
# and won't be executed.
# 4. Have __del__ invoke this, which doesn't work -- it only happens after
# ~ThreadController has finihed.
def del_(self):
print('del_')
self.workerThread.quit()
self.workerThread.wait()
def __del__(self):
print('__del__')
# Crash when uncommented.
#self.del_()
if __name__ == '__main__':
app = QApplication(sys.argv)
# Exit the program shortly after the event loop starts up, but before the
# thread finishes.
QTimer.singleShot(200, app.exit)
# Start a thread
tm = ThreadController(app)
# Run the main event loop.
ret = app.exec_()
print('done')
sys.exit(ret)
</code></pre>
<div title="MDH:QWxsLDxkaXY+PGJyPjwvZGl2PjxkaXY+SSdtIGNvbmZ1c2VkIHdoZW4gaXQgY29tZXMgdG8gdGhl
IHByb3BlciB3YXkgdG8gbWVzaCBRdCdzIG1vZGVsIG9mIGNyZWF0aW5nIGEgdHJlZSBvZiBwYXJl
bnRlZCBvYmplY3RzIHdoaWNoIGRlc3Ryb3kgdGhlbXNlbHZlcyB3aGVuIG5vIGxvbmdlciB1c2Vk
IHdpdGggUHl0aG9uJ3MgImRlbGV0ZSBpdCB3aGVuIEkgZmVlbCBsaWtlIGl0IiBnYXJiYWdlIGNv
bGxlY3Rvci4gSW4gcGFydGljdWxhciwgSSdkIGxpa2UgdG8gc2h1dCBkb3duIHRocmVhZHMgd2hl
biB0aGUgdW5kZXJseWluZyBRdCBvYmplY3RzIGFyZSBkZXN0cm95ZWQsIGJ1dCBJIGNhbid0IGZp
Z3VyZSBvdXQgaG93IHRvIGRvIHRoYXQuIEFueSBhZHZpY2UgYW5kIHdpc2RvbSB3b3VsZCBiZSBh
cHByZWNpYXRlZC48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2PkJyeWFuPC9kaXY+PGRpdj48YnI+
PC9kaXY+PGRpdj48ZGl2PiZuYnNwOyAmbmJzcDsgIyBUZXN0IHByb2dyYW0gdG8gYXNrIGFib3V0
IGRlc3RydWN0b3JzIGFuZCBQeVF0NC48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsmbmJzcDs8L2Rp
dj48ZGl2PiZuYnNwOyAmbmJzcDsgaW1wb3J0IHN5cywgdGltZTwvZGl2PjxkaXY+Jm5ic3A7ICZu
YnNwOyBmcm9tIFB5UXQ0LlF0R3VpIGltcG9ydCBRQXBwbGljYXRpb248L2Rpdj48ZGl2PiZuYnNw
OyAmbmJzcDsgZnJvbSBQeVF0NC5RdENvcmUgaW1wb3J0IFFUaHJlYWQsIFFUaW1lciwgUU9iamVj
dDwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyZuYnNwOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyBj
bGFzcyBXb3JrZXIoUU9iamVjdCk6PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJz
cDsgZGVmIHJ1bihzZWxmKTo8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7IHRpbWUuc2xlZXAoMSk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsmbmJzcDs8
L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgY2xhc3MgVGhyZWFkQ29udHJvbGxlcihRT2JqZWN0KTo8
L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBkZWYgX19pbml0X18oc2VsZiwg
cGFyZW50KTo8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7IFFPYmplY3QuX19pbml0X18oc2VsZiwgcGFyZW50KTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBObyBwYXJlbnQgb2JqZWN0IHByb3ZpZGVk
OyBpZiBzbywgd2UgZ2V0IHRoZSBlcnJvcjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAiUU9iamVjdDo6bW92ZVRvVGhyZWFkOiBDYW5ub3QgbW92
ZSBvYmplY3RzIHdpdGggYSBwYXJlbnQiLjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBXaG8gd2lsbCBkZWFsbG9jYXRlIHRoaXMgb2JqZWN0LCBz
aW5jZSBpdCBoYXMgbm8gcGFyZW50PyBJPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAjIGFzc3VtZSB0aGUgYW5zd2VyIGlzICJQeXRob24sIG1heWJl
Ii4gSXMgdGhhdCBnb29kIGVub3VnaD88L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgJm5ic3A7IHNlbGYud29ya2VyID0gV29ya2VyKCk8L2Rpdj48ZGl2PiZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IHNlbGYud29ya2VyVGhyZWFkID0g
UVRocmVhZChzZWxmKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyAmbmJzcDsgc2VsZi53b3JrZXIubW92ZVRvVGhyZWFkKHNlbGYud29ya2VyVGhyZWFkKTwvZGl2
PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBVc2UgbWV0
aG9kICMyIGJlbG93LiBDb21tbmV0IG91dCBmb3IgYSBjcmFzaC48L2Rpdj48ZGl2PiZuYnNwOyAm
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IHBhcmVudC5hYm91dFRvUXVpdC5jb25u
ZWN0KHNlbGYuZGVsXyk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJz
cDsgJm5ic3A7IHNlbGYud29ya2VyVGhyZWFkLnN0YXJ0KCk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJz
cDsmbmJzcDs8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIEknZCBsaWtl
IHRvIHJ1biB3aGVuIHdoZW4gflRocmVhZENvbnRyb2xsZXIgaXMgaW52b2tlZC4gVGhhdCdzIHF1
aXRlPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyBkaWZmZXJlbnRmcm9t
IHdoZW4gX19kZWxfXyBpcyBpbnZva2VkLiBIb3c/PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZu
YnNwOyAmbmJzcDsgIzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgMS4g
R2l2ZSB1cC4gSnVzdCBpbnZva2UgaXQgbWFudWFsbHkuIEhvd2V2ZXIsIHRoaXMgaXMgZXJyb3It
cHJvbmUgKGkuZS48L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICZuYnNw
OyAmbmJzcDtJJ2xsIGZvcmdldCB0byBkbyBpdCBhdCBzb21lIHBvaW50KS48L2Rpdj48ZGl2PiZu
YnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIDIuIENvbm5lY3QgYXBwLmFib3V0VG9RdWl0IHRv
IHRoaXMuIFRoaXMgc2VlbXMgZmFpcmx5IHJlYXNvbmFibGUsIGJ1dDwvZGl2PjxkaXY+Jm5ic3A7
ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgJm5ic3A7ICZuYnNwO2l0IHdvdWxkIGZlZWwgY2xlYW5l
ciB0byBpbnZva2Ugd2hlbiB0aGUgZGVzdHJ1Y3RvciBpcyBpbnZva2VkLDwvZGl2PjxkaXY+Jm5i
c3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgJm5ic3A7ICZuYnNwO3JhdGhlciB0aGFuIGVhcmxp
ZXIuIEFsc28sIHRoaXMgbWVhbnMgdGhhdCB0aGUgUUFwcGxpY2F0aW9uIHdvdWxkPC9kaXY+PGRp
dj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAmbmJzcDsgJm5ic3A7bmVlZCB0byBiZSBw
YXNzZWQgdG8gZXZlcnkgdGhyZWFkLCB3aGljaCBtaWdodCBpbnZvbHZlIGF3a3dhcmRuZXNzPC9k
aXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAmbmJzcDsgJm5ic3A7aW4gcGFz
c2luZyBpdCB0aHJvdWdoIHNldmVyYWwgaW50ZXJ2ZW5pbmcgc3ViY2xhc3Nlcy48L2Rpdj48ZGl2
PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIDMuIENvbm5lY3QgZGVzdHJveWVkKCksIHdo
aWNoIGRvZXNuJ3Qgd29yayAtLSB0aGlzIGlzbid0IGVtaXR0ZWQgdW50aWw8L2Rpdj48ZGl2PiZu
YnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjICZuYnNwOyAmbmJzcDt0aGUgb2JqZWN0IGlzIG1v
c3RseSBkZWFkLCBmYXIgYWZ0ZXIgflRocmVhZENvbnRyb2xsZXIgd2FzIGludm9rZWQsPC9kaXY+
PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAmbmJzcDsgJm5ic3A7YW5kIHdvbid0
IGJlIGV4ZWN1dGVkLjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgNC4g
SGF2ZSBfX2RlbF9fIGludm9rZSB0aGlzLCB3aGljaCBkb2Vzbid0IHdvcmsgLS0gaXQgb25seSBo
YXBwZW5zIGFmdGVyPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgIyAmbmJz
cDsgJm5ic3A7flRocmVhZENvbnRyb2xsZXIgaGFzIGZpbmloZWQuPC9kaXY+PGRpdj4mbmJzcDsg
Jm5ic3A7ICZuYnNwOyAmbmJzcDsgZGVmIGRlbF8oc2VsZik6PC9kaXY+PGRpdj4mbmJzcDsgJm5i
c3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBwcmludCgnZGVsXycpPC9kaXY+PGRpdj4m
bmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBzZWxmLndvcmtlclRocmVh
ZC5xdWl0KCk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5i
c3A7IHNlbGYud29ya2VyVGhyZWFkLndhaXQoKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyZuYnNw
OzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IGRlZiBfX2RlbF9fKHNlbGYp
OjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgcHJp
bnQoJ19fZGVsX18nKTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyAmbmJzcDsgIyBDcmFzaCB3aGVuIHVuY29tbWVudGVkLjwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNw
OyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgI3NlbGYuZGVsXygpPC9kaXY+PGRpdj4mbmJz
cDsgJm5ic3A7Jm5ic3A7PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7IGlmIF9fbmFtZV9fID09ICdf
X21haW5fXyc6PC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgYXBwID0gUUFw
cGxpY2F0aW9uKHN5cy5hcmd2KTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyZuYnNwOzwvZGl2Pjxk
aXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgRXhpdCB0aGUgcHJvZ3JhbSBzaG9ydGx5
IGFmdGVyIHRoZSBldmVudCBsb29wIHN0YXJ0cyB1cCwgYnV0IGJlZm9yZSB0aGU8L2Rpdj48ZGl2
PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAjIHRocmVhZCBmaW5pc2hlcy48L2Rpdj48ZGl2
PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyBRVGltZXIuc2luZ2xlU2hvdCgyMDAsIGFwcC5l
eGl0KTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyZuYnNwOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNw
OyAmbmJzcDsgJm5ic3A7ICMgU3RhcnQgYSB0aHJlYWQ8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsg
Jm5ic3A7ICZuYnNwOyB0bSA9IFRocmVhZENvbnRyb2xsZXIoYXBwKTwvZGl2PjxkaXY+Jm5ic3A7
ICZuYnNwOyZuYnNwOzwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICMgUnVu
IHRoZSBtYWluIGV2ZW50IGxvb3AuPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJz
cDsgcmV0ID0gYXBwLmV4ZWNfKCk8L2Rpdj48ZGl2PiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNw
OyBwcmludCgnZG9uZScpPC9kaXY+PGRpdj4mbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgc3lz
LmV4aXQocmV0KTwvZGl2PjxkaXY+Jm5ic3A7ICZuYnNwOyZuYnNwOzwvZGl2PjxkaXY+PGJyPjwv
ZGl2PjwvZGl2Pg==" style="min-height:0;font-size:0em;padding:0;margin:0">
</div>
</div>
<div>-- <br>
Bryan A. Jones, Ph.D.<br>
Associate Professor<br>
Department of Electrical and Computer Engineering<br>
231 Simrall / PO Box 9571<br>
Mississippi State University<br>
Mississippi state, MS 39762<br>
<a href="http://www.ece.msstate.edu/~bjones" target="_blank">http://www.ece.msstate.edu/~bjones</a><br>
bjones AT ece DOT msstate DOT edu<br>
voice <a href="tel:662-325-3149" value="+16623253149" target="_blank">662-325-3149</a><br>
fax <a href="tel:662-325-2298" value="+16623252298" target="_blank">662-325-2298</a><br>
<br>
Our Master, Jesus Christ, is on his way. He'll show up right on<br>
time, his arrival guaranteed by the Blessed and Undisputed Ruler,<br>
High King, High God.<br>
- 1 Tim. 6:14b-15 (The Message)<br>
</div>
</div>
</blockquote>
</div></div></div><div><div class="h5">
<br>
<br clear="all">
<div><br>
</div>
-- <br>
Bryan A. Jones, Ph.D.<br>
Associate Professor<br>
Department of Electrical and Computer Engineering<br>
231 Simrall / PO Box 9571<br>
Mississippi State University<br>
Mississippi state, MS 39762<br>
<a href="http://www.ece.msstate.edu/~bjones" target="_blank">http://www.ece.msstate.edu/~bjones</a><br>
bjones AT ece DOT msstate DOT edu<br>
voice <a href="tel:662-325-3149" value="+16623253149" target="_blank">662-325-3149</a><br>
fax <a href="tel:662-325-2298" value="+16623252298" target="_blank">662-325-2298</a><br>
<br>
Our Master, Jesus Christ, is on his way. He'll show up right on<br>
time, his arrival guaranteed by the Blessed and Undisputed Ruler,<br>
High King, High God.<br>
- 1 Tim. 6:14b-15 (The Message)<br>
</div></div></div>
</div>
</blockquote></div><br><br clear="all"><div><br></div>-- <br>Bryan A. Jones, Ph.D.<br>Associate Professor<br>Department of Electrical and Computer Engineering<br>231 Simrall / PO Box 9571<br>Mississippi State University<br>Mississippi state, MS 39762<br><a href="http://www.ece.msstate.edu/~bjones" target="_blank">http://www.ece.msstate.edu/~bjones</a><br>bjones AT ece DOT msstate DOT edu<br>voice 662-325-3149<br>fax 662-325-2298<br><br>Our Master, Jesus Christ, is on his way. He'll show up right on<br>time, his arrival guaranteed by the Blessed and Undisputed Ruler,<br>High King, High God.<br>- 1 Tim. 6:14b-15 (The Message)<br>
</div>