Python threads with os.system () calls. The main thread does not go to ctrl + c

Please do not consider it a duplicate before reading. There are many questions about multithreading and keyboard interrupt , but I did not find any os.system in question and it seems to be important.

I have a python script that calls some external calls in worker threads. I want it to exit if I press ctrl+c But it seems like the main thread is ignoring it.

Something like that:

 from threading import Thread import sys import os def run(i): while True: os.system("sleep 10") print i def main(): threads=[] try: for i in range(0, 3): threads.append(Thread(target=run, args=(i,))) threads[i].daemon=True threads[i].start() for i in range(0, 3): while True: threads[i].join(10) if not threads[i].isAlive(): break except(KeyboardInterrupt, SystemExit): sys.exit("Interrupted by ctrl+c\n") if __name__ == '__main__': main() 

Surprisingly, it works fine if I change os.system("sleep 10") to time.sleep(10) .

+4
source share
2 answers

I am not sure which operating system and shell you are using. I am describing Mac OS X and Linux using zsh (bash / sh should do the same).

When you press Ctrl + C, all programs running in the foreground in the current terminal receive a SIGINT signal . In your case, this is your main python process and all processes generated by os.system.

The processes spawned by os.system then terminate their execution. Usually, when a python script gets SIGINT, it throws a KeyboardInterrupt exception, but your main process ignores SIGINT due to os.system() . Python os.system() calls the standard C system() function , which causes the call process to ignore SIGINT ( man Linux / man Mac OS X ).

This way none of your python threads gets SIGINT, only children process it.

When you delete the os.system () call, your python process stops ignoring SIGINT and you get KeyboardInterrupt .

You can replace os.system("sleep 10") with subprocess.call(["sleep", "10"]) . subprocess.call() does not force your process to ignore SIGINT.

+4
source

I had the same problem more times than I could have expected when I first studied python multithreading.

Adding a sleep call in a loop makes your main thread block, which allows it to still hear and abide by exceptions. What you want to do is use the Event class to set the event in the child threads, which will serve as the exit flag to abort. You can set this flag to your KeyboardInterrupt exception, just put an except clause for this in your main thread.

I'm not quite sure what happens with different types of behavior between a particular python sleep and named one of them, but the tool I offer should work for what is your desired end result. Just by suggesting, is the os called likely blocking the interpreter itself differently?

Keep in mind that in most cases when threads are needed, the main thread will continue to do something, in which case it means β€œsleeping” in your simple example.

http://docs.python.org/2/library/threading.html#event-objects

+1
source

All Articles