Processes, syscalls, signals
A process is a row in a table the kernel keeps: a parent, a program, a set of open files, a state, and eventually an exit code. Fork copies a row, exec changes its program, wait deletes it, and a signal can end it. Every run on this page is one the build made.
What is a zombie process, and how do you get rid of one?
A zombie is a process that has exited but whose parent has not yet called wait for it. The kernel keeps a minimal record of it (its process id, its exit status, its resource usage) so the parent can still collect how it ended. It runs no code; what it holds is a slot in the process table. You cannot kill a zombie, because it is already dead. You fix the parent so it calls wait, or you end the parent, at which point the zombie is adopted by the first process (or a subreaper), which waits for it.
What is the difference between fork and exec?
fork creates a new process that is a copy of the caller: the same program, a copy of its memory, a copy of its descriptor table. It returns twice, with the child’s process id in the parent and 0 in the child. exec creates nothing. It replaces the program running in the current process with a new one, keeps the same process id, and does not return if it succeeds. A shell runs a command with both: fork to get a new process, then exec in the child to turn it into the command.
What happens to open file descriptors when a process forks?
The child gets a copy of the parent’s descriptor table, and each copied descriptor points at the same open file description as the parent’s. The fork(2) manual says the two then share file status flags and the file offset. So if the parent and the child both write through a descriptor they had before the fork, the writes land one after the other and neither overwrites the other. Two separate calls to open the same file make two descriptions with two offsets, and then writes do overwrite each other.
What does kill send by default, and why does kill -9 always work?
kill with no signal sends SIGTERM, whose default action is to end the process. A process can install a handler for SIGTERM and clean up first, which is why it is the one to send first. SIGKILL, number 9, cannot be caught, blocked or ignored, so no handler runs and the process gets no chance to clean up. It does not end a zombie, because a zombie has already exited: only a wait removes it.
Should I use processes or threads in Python?
Use processes when the work is computing in Python and you need more than one core, because each process has its own interpreter. Use threads when the work spends its time waiting on input and output. Processes share no memory, so arguments and results are copied between them, and a fork copies everything the parent had in memory at that moment, including the state of locks held by threads that do not exist in the child. Since Python 3.12, os.fork raises a DeprecationWarning when Python can tell the process has several threads.