3

I've been playing along with threads in Python, and I came across something interesting with the following code:

import time
import threading

class Update(threading.Thread):
  def __init__(self):
    threading.Thread.__init__(self)
    self.stop_event = threading.Event()

  def join(self, timeout=None):
    self.stop_event.set()
    threading.Thread.join(self, timeout)

  def run(self):
    while not self.stop_event.isSet():
      print("test")

thread = Update()
thread.start()

This code randomly stops even if I don't call the join() method. As a result, I get different outputs like these:

test@debian:~/$ python3 test.py
test
test
test
test
test@debian:~/$ python3 test.py
test
test
test
test
test
test
test
test@debian:~/$ python3 test.py
test
test

Why is this code randomly stopping? I thought that only by setting stop_event this thread would stop.

P .Tranca
  • 35
  • 1
  • 5
  • 1
    Please note that print is not thread-safe: http://stackoverflow.com/questions/18234469/python-multithreaded-print-statements-delayed-until-all-threads-complete-executi – João Pinto Apr 18 '16 at 17:02
  • @JoãoPinto: That question isn't actually about thread-safety. It doesn't even *use* any threads; it forks a bunch of processes instead, and I don't think the processes had anything to do with the problem. – user2357112 Apr 18 '16 at 17:17
  • Comments are not answers, my comment is provided in the context that the user is attempting to debug a multi-threaded application using prints to stdout. – João Pinto Apr 19 '16 at 10:48

2 Answers2

4

You already got the essential answer, but there's a detail you need to be aware of: when the main program ends, as part of shutdown processing Python calls .join() on all non-daemon threads created by the threading module. You overrode .join(), so Python calls your .join(). That in turn sets the event, and so your .run() method exits silently.

Tim Peters
  • 67,464
  • 13
  • 126
  • 132
  • So *that's* why the non-daemon thread isn't blocking the shutdown. It makes sense; Python needs to wait for non-daemon threads to finish, so it calls the method specifically designed to wait for a thread to finish. – user2357112 Apr 18 '16 at 17:08
  • 1
    Also, it's easy to show that this is what happens - add a print statement to the join method and you'll see that the join method gets called. – Rob Watts Apr 18 '16 at 17:10
2

When the main thread ends the program ends.

The number of times that the thread loops before the main one stops is fairly arbitrary. (up to the OS to schedule)

Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59
  • The [docs](https://docs.python.org/2/library/threading.html#thread-objects) say all non-daemon threads need to end before the program ends. – user2357112 Apr 18 '16 at 17:02
  • @user2357112 Yes I was just looking for proof that garbage collection closed the thread when the program ends but it seems that garbage collection has nothing to do with it and TimPeters has provided the correct answer to how the thread is closed. – Tadhg McDonald-Jensen Apr 18 '16 at 17:08