Python threading.Thread, scopes and garbage collection Python threading.Thread, scopes and garbage collection multithreading multithreading

Python threading.Thread, scopes and garbage collection


How about using a wrapper class (which has-a Thread rather than is-a Thread)?

eg:

class WorkerWrapper:    __init__(self):        self.worker = Worker()    __del__(self):        self.worker.terminate()

And then use these wrapper classes in client code, rather than threads directly.

Or perhaps I miss something (:


To add an answer inspired by @datenwolf's comment, here is another way to do it that deals with the object being deleted or the parent thread ending:

import threadingimport timeimport weakrefclass Foo(object):    def __init__(self):        self.main_thread = threading.current_thread()        self.initialised = threading.Event()        self.t = threading.Thread(target=Foo.threaded_func,                args=(weakref.proxy(self), ))        self.t.start()        while not self.initialised.is_set():            # This loop is necessary to stop the main threading doing anything            # until the exception handler in threaded_func can deal with the             # object being deleted.            pass    def __del__(self):        print 'self:', self, self.main_thread.is_alive()        self.t.join()    def threaded_func(self):        self.initialised.set()        try:            while True:                print time.time()                if not self.main_thread.is_alive():                    print('Main thread ended')                    break                time.sleep(1)        except ReferenceError:            print('Foo object deleted')foo = Foo()del foofoo = Foo()


I guess you are a convert from C++ where a lot of meaning can be attached to scopes of variables, equalling lifetimes of variables. This is not the case for Python, and garbage collected languages in general.Scope != Lifetime simply because garbage collection occurs whenever the interpreter gets around to it, not on scope boundaries. Especially as you are trying to do asynchronuous stuff with it, the raised hairs on your neck should vibrate to the clamour of all the warning bells in your head!You can do stuff with the lifetime of objects, using 'del'.(In fact, if you read the sources to the cpython garbage collector module, the obvious (and somewhat funny) disdain for objects with finalizers (del methods) expressed there, should tell everybody to use even the lifetime of an object only if necessary).

You could use sys.getrefcount(self) to find out when to leave the loop in your thread. But I can hardly recommend that (just try out what numbers it returns. You won't be happy. To see who holds what just check gc.get_referrers(self)).The reference count may/will depend on garbage collection as well.

Besides, tying the runtime of a thread of execution to scopes/lifetimes of objects is an error 99% of the time. Not even Boost does it. It goes out of its RAII way to define something called a 'detached' thread.http://www.boost.org/doc/libs/1_55_0/doc/html/thread/thread_management.html