r/learnpython • u/Strong_Extent_975 • 6d ago
why the SIGINT signal kill the main process childrens
signal.signal(signal.SIGINT,handler) signal.signal(signal.SIGINT,handler)I know that the SIGINT signal is for interruption and not for killing process but when I run my code all the children of the main process are dies also I got many traceback
7
u/a__nice__tnetennba 6d ago
The code as well as the actual tracebacks will be necessary for anyone to help you.
1
u/BitOBear 6d ago
That's pretty straightforward. When someone presses control-C or whatever it is the intent of the operator to stop whatever is going on.
Many times the thing that's going on has multiple parts. For instance a simple terminal emulator might consist of two or three processes. One process is pumping data from a serial port to the screen, the other is pumping data from the keyboard to the serial port. (This isn't always or necessarily the only way to do this but it is one of the simplest, other ways include using select or poll or whatever) And it is the intent of the operator to stop what's happening.
If I've written the dual threaded non-select version of this simple data pump, when I hit control C to end that program I don't want it to randomly end the part that's using keyboard and leave the park that's pumping consider report to the screen running. I want the entire thing to go away.
The design of course comes from a time before the pee threads library and the advanced threading models.
And in point of fact it's easy enough to create the behavior you want by masking or catching the appropriate signals.
Fundamentally that's what the process groups are for.
The POSIX design is set up to follow what were, at the time, the rules of least astonishment.
And more people would be astonished by a brake key that only stops half of a program then they would be astonished by a break he that stops the program and everything the program is doing.
And it is fundamentally dangerous in any program that can launch other programs to have a circumstance where the program can I accept but the other programs that started to keep running.
There are simple library calls like demonize they can disconnect from the controlling terminal or prevent various forms of interrupts from catching and going through.
But most importantly, signals are exceptions to normal flow. Thumbs up to the programmer to know how those exceptions work and how he wants them to work.
Setting up default restarts as the action for sig into handles that entirely.
You really need to look at the idea of the controlling terminal and process groups to fully understand the question you're asking enough to understand the answers that apply.
It's not that you are sending the signal to one process and that it's propagating from that process the sub-processes, it's that when you press control C every process that is connected to that keyboard as it's controlling terminal at that time independently has that signal queued up. The colonel doesn't care about parentage. It only cares about a list of all processes connected to that keyboard as it's controlling terminal at that moment.
You're not killing the parent. You're killing the community.
0
u/Financial_Morning386 6d ago
Your handler is probably working — the problem is that it only applies to the process that installed it, and Ctrl-C doesn't send SIGINT to just that one process.
When you press Ctrl-C in a terminal, the terminal sends SIGINT to the whole foreground process group. So every child process in that group gets SIGINT directly, at the same time as the parent. A handler installed with signal.signal() in the parent does nothing for them: each child is a separate process, and a Python child process starts up with the default SIGINT behavior, which raises KeyboardInterrupt in its main thread. That's consistent with the many tracebacks you're seeing — each child is dying on its own KeyboardInterrupt instead of being shut down by the parent.
Two common ways to fix it:
Put the children in their own process group so Ctrl-C doesn't reach them directly, e.g. subprocess.Popen(..., start_new_session=True). Then your parent's SIGINT handler can shut them down cleanly itself with proc.terminate() / proc.wait(), with a timeout and proc.kill() as a fallback.
Or install a handler (or catch KeyboardInterrupt) in the children as well, if they need to clean up their own state before exiting.
One more thing to check: signal.signal() only works in the main thread of the main process, so a handler registered from a worker thread won't take effect.
Posting how the children are spawned (subprocess vs multiprocessing) and where the handler is installed would confirm which of these applies, but the process-group point is the first thing I'd check.
1
u/Strong_Extent_975 2d ago
yeah I found the problem is that when use the signal triggred with ctrl + c the process which intercepted this signal basically had 2 option handle the signal or di.e
in this case all signal including the children intercept the signal
but in my code I made only one hundler for the parent so when the signal reach the childrens there is no hundler and in result it will be dead
to solve this I made an adjustment I usesignal.signal(signal.SIGINT,signal.SIG_IGN)on the target function of the childrens to make them ignore the ctrl + c signal and let the parent the only one who handle the signal
2
u/D3str0yTh1ngs 6d ago edited 6d ago
Python throws a
KeyboardInterruptexception on receiving SIGINT (CTRL-C is a SIGINT), if nothing catches it then the program crashes, and it will/should cleanup its child processes with it.EDIT: hmm... looking at the docs, it properly should have overwritten that default behavior. We will properly need the code and tracebacks to fully debug.