1

I'd like to monitor a process and auto-kill it if it runs more than N seconds.

I'm editing this question in response to the suggestion that it's a duplicate of: Is there any way to kill a Thread in Python?

I'd argue that my question is slightly different in that I'm focused on basic cleanup AFTER thread completion (which might actually be more difficult than the aforementioned possible duplicate as everyone seems to say it's impossible).

As a simple test, I'm attempting the following to try and kill the process after 2 seconds:

import threading
import sys
import time

def after_timeout():
  print "KILL THE WORLD HERE!"
  # whats the secret sauce here (if any)?
  # sys.exit() and other variants aren't
  # killing the main thread... is it possible?

threading.Timer(2, after_timeout).start()

i = 0
while True:
  print i
  i += 1
  time.sleep(1)
slumtrimpet
  • 3,159
  • 2
  • 31
  • 44
  • 1
    https://stackoverflow.com/questions/34562473/most-pythonic-way-to-kill-a-thread-after-some-period-of-time?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – MoxieBall May 22 '18 at 17:26
  • I'm 99% sure I'm being dumb and just missing something very basic here. But... I can't necessarily guarantee that my long running process is actually iterating so I can't necessarily guarantee that it will ever hit the 'if e.is_set()' in a solution like that. – slumtrimpet May 22 '18 at 17:35
  • Possible duplicate of [Is there any way to kill a Thread in Python?](https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in-python) – zvone May 22 '18 at 17:46
  • @zvone hrmm... I possibly agree. :-) Reading through the answers to that question now. – slumtrimpet May 22 '18 at 17:48
  • @zvone just posted an update to my question as well as my current proposed solution for critique :-) – slumtrimpet May 22 '18 at 18:28
  • @slumtrimpet Ah, I though you were trying to kill individual threads, but you are killing the whole process. That is different... and simpler. – zvone May 22 '18 at 18:57
  • @slumtrimpet Perhaps you should make your answer an actual answer. Anyway, my main concern would be how certain it is that the `atexit` will actually be triggered for each of the daemon threads. And I don't have an answer for that. – zvone May 22 '18 at 18:59
  • Split my proposed solution into an actual answer per @zvone suggestion. – slumtrimpet May 22 '18 at 19:07

2 Answers2

2

So... I think may have solved this by combining 10 different SO posts in a way that I've not seen on any single SO post... please critique and tell me if this is dumb or brilliant... ;-)

[Because this question is very closely related to at least two others... I've posted my proposed solution as an independent answer in the both related threads: 1 2]

import threading
import time
import atexit

def do_work():

  i = 0
  @atexit.register
  def goodbye():
    print ("'CLEANLY' kill sub-thread with value: %s [THREAD: %s]" %
           (i, threading.currentThread().ident))

  while True:
    print i
    i += 1
    time.sleep(1)

t = threading.Thread(target=do_work)
t.daemon = True
t.start()

def after_timeout():
  print "KILL MAIN THREAD: %s" % threading.currentThread().ident
  raise SystemExit

threading.Timer(2, after_timeout).start()

Yields:

0
1
KILL MAIN THREAD: 140013208254208
'CLEANLY' kill sub-thread with value: 2 [THREAD: 140013674317568]

I think that's the secret sauce that will work for my application. My sub-thread is cleaned up properly now after a fixed amount of time with no looping flag check nonsense within said sub-thread... AND I appear to even get a small glimmer of control in the subthread where I can do some final state checking and cleanup.

slumtrimpet
  • 3,159
  • 2
  • 31
  • 44
0

When I tried your code it appears that the "secret sauce" is actually the daemon=True flag not the raise SystemExit, and that the code doesn't work as you would expect. I mean, if you write something like this at the end:

print("still continuing")
time.sleep(5)
print("by now, the second thread should have already be killed, but it's not...")
print("exiting, naturally, by closing the main thread..., just now the second thread will also close, being a daemon thread")

Still this is useful, it means you don't have to kill your thread, you can make your main program/thread to exit as early as possible, after waiting for some timeouts, but before exiting, it can signal the timeout-err on a persistent way on disk or on a db. Exiting your main thread is the most efficient way to kill your other threads, I'm assuming in this point, and it works out great for me, as my main program was designed to only run a single iteration on its logic, and be respawned by a systemctl strong mechanism.

user602445
  • 1
  • 1
  • 4