Page 1 of 1
Is it required to join a thread in Python?
Posted: Mon Aug 21, 2017 5:05 pm
by Boolean263
In the languages I'm used to, when you create a new thread, you either need to join() it eventually to your main thread, or else take extra steps to ensure the main thread that it doesn't need to wait for the separate thread to finish. If you don't do either of these steps, you can accumulate zombie processes.
The python
threading documentation mentions the join() method, but doesn't give the usual warnings about what could happen if you don't join your threads. Does this mean that I can just spin off a thread and ignore it if I don't care about its results?
Context: A plugin I'm working on calls a function that blocks the EventGhost UI (and possibly other processing) if I call it directly. If I wrap it in a Thread() call the problem goes away. But I don't want to cause other problems.
Thanks!
Edit: I found a better way to handle my problem with EG, so I don't need to use threads any more, but I'm still curious to know what the word is on python thread joining or not.
Re: Is it required to join a thread in Python?
Posted: Wed Aug 23, 2017 2:00 am
by Boolean263
I've done some more reading on the threading module. If one sets the 'daemon' attribute to True on a child thread object before calling start() on it, then python will exit when the main thread exits (the documentation says the child threads are "abruptly stopped" in this case). Contrast to non-daemon threads, which continue running on their own, and keep the python interpreter running.
It still wasn't clear to me what happens for child threads which run to completion while the main thread is still running. So I puttered around a bit and wrote this test script:
Code: Select all
def childproc():
print("Child starting")
sleep(5)
print("Child exiting")
def pseudomain():
print("'Main' starting")
t = threading.Thread(target=childproc)
t.daemon = True
t.start()
for i in range(1,10):
print("...")
sleep(1)
print threading.enumerate()
print("'Main' finished")
pseudomain()
print("Main starting")
sleep(3)
print threading.enumerate()
print("Main exiting")
When the sleep in childproc() is less than 10 seconds, then the call to threading.enumerate() shows both threads for the first few loops, and then only the main thread after the child runs to completion, whether or not it was a daemon thread. So I guess that answers my question: python will clean up threads itself that run to completion. join()ing a thread, then, must only be a requirement if you need something the thread provides, and you want to make sure it's done so.
So yeah, today I learned. I hope you found it as informative as I did.
Re: Is it required to join a thread in Python?
Posted: Wed Aug 23, 2017 7:50 am
by kgschlosser
if you are stopping the thread then yes. this causes the program to join the thread and to wait until it exits.
also the best way to go about using threads is to use threading.Event to do wait intervals instead of something like time.sleep. for many reasons but the #1 reason is because it is non blocking for when you want to shutdown the thread. I posted some example code
Code: Select all
import threading
event = threading.Event()
count = 0
def run()
global count
while not event.isSet():
print count
event.wait(1.0)
count += 1
t = threading.Thread(target=run)
t.start()
while count <= 5:
pass
# when you call set() it forces the wait() to exit before the timeout period has expired.
# set() can also be called from inside of the thread loop if an error has occurred and you
# do not want the thread to continue. this you do not have to worry about calling join()
# because the thread is terminating it's self. there are situations where you may not
# have to call join(). these cases are when you want to exit the thread and there is
# no other code dependent on the thread running or not.
event.set()
t.join(2.0)
Re: Is it required to join a thread in Python?
Posted: Wed Aug 23, 2017 7:58 am
by kgschlosser
and what a daemon thread is is a thread that will terminate of the parent thread does. no matter what it is doing. so we have to create a thread that creates a daemon thread and have the first one exit as normal and the daemon thread will be forced to end. You have to be careful doing this because if it is in the middle of something like a file operation you will get corruption.
Code: Select all
import time
import threading
event1 = threading.Event()
event2 = threading.Event()
def run2():
event2.wait()
def run1():
t2 = threading.Thread(target=run2)
t2.daemon = True
t2.start()
print threading.enumerate()
event1.wait()
t1 = threading.Thread(target=run1)
t1.start()
time.sleep(1)
print threading.enumerate()
event1.set()
t1.join(1.0)
time.sleep(1)
print threading.enumerate()