TheRealFakeNews
TheRealFakeNews

Reputation: 8153

Python: Unable to kill process with keyboard interrupt?

I have a decorator written as such:

import threading
from time import sleep
from functools import wraps
import sys
import os

def repeat_periodically(f):
    """ Repeat wrapped function every second """
    @wraps(f)
    def wrap(self, *args, **kwargs):
        def wrap_helper(*args, **kwargs):
            try:
                threading.Timer(1.0, wrap_helper).start()
                f(self)
            except KeyboardInterrupt:
                try:
                    sys.exit(1)
                except:
                    os._exit(1)

        wrap_helper()

    return wrap

I'm not sure if it continues to open a new thread every single time it calls itself, but regardless, I'm unable to kill the process when I hit CTRL + C. I've also added the same try-except block in the function that I've decorated:

@repeat_periodically
def get_stats(self):
    try:
        # log some state information
    except KeyboardInterrupt:
        try:
            sys.exit(1)
        except:
            os._exit(1)

My program just continues to run and all I see in the terminal is

^C <the stuff that I am logging>
<the stuff that I am logging>
<the stuff that I am logging>

In other words, it just keeps logging, even though I'm trying to kill it with CTRL + C.

Update:

I should mention that the above process is spun up from another thread:

tasks = [
    {'target': f, 'args': (arg1)},
    {'target': g},
]
for task in tasks:
    t = threading.Thread(**task)
    t.start()

Specifically it is the second task that spins up the Timer. However, if I set t.daemon = True, the process just runs once and exits. The first task uses watchdog. I've essentially used the example code from the watchdog documentation:

def watch_for_event_file(Event):
    path = sys.argv[1] if len(sys.argv) > 1 else '.'
    event_handler = LoggingCreateHandler(Event)
    observer = Observer()
    observer.schedule(event_handler, path)
    observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()

(Sorry for all the updates)

Upvotes: 1

Views: 1983

Answers (2)

ashutosh pranjal
ashutosh pranjal

Reputation: 1

  1. Check for Background Processes: a.Open Task Manager by pressing Ctrl +Shift+ Esc b.Look for any lingering Python processes in the "Processes" or "Details" tab. c.If you find a Python process, right-click on it and choose "End Task."

After doing this open your cmd and hit CTRL+C again you would be able to kill the previous python process.

Upvotes: 0

John Anderson
John Anderson

Reputation: 38892

From the Thread documentation:

The entire Python program exits when no alive non-daemon threads are left.

So making your Timer threads as daemon threads should solve your problem. So replace:

threading.Timer(1.0, wrap_helper).start()

with:

t = threading.Timer(1.0, wrap_helper)
t.daemon = True
t.start()

Upvotes: 2

Related Questions