[Linux] Orphan Processes, Dead Processes, and Signals

I. Orphan Process

The parent process ends, the child process does not end, and the child process is left to the init process to care for

2. Zombie Processes

When the parent process does not end, the child process has ended and the parent process does not process the exit status of the child process.

A process consists of process entities and process control blocks, which are released when the process ends.

** Formation of a zombie process: ** The process has ended and the process entity has been released, but the system has not released the corresponding process control block (PCB);

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

int main()
{
	pid_t pid = fork();
	assert(pid != -1);
	
	if(pid == 0)
	{	
		printf("child start\n");
		sleep(3);
		printf("child end\n");
	}
	else
	{
		sleep(10);
	}
	return 0;
}

(1) Create a deadly process


Be careful:
With a 2.4G kernel, a PCB consumes about 1.7k of memory, while the parent process is usually a server process, which generally does not end. If he doesn't handle the zombie process, he will always exist. Bash: For each command executed, bash fork s a subprocess. If there are a lot of zombie processes, memory will be consumed and slowed down.

(2) Dealing with the zombie process

The operating system provides a set of system calls:

pid_t wait(int *result);// The pid of the child process is handled when the value is returned, and the parameter is the status code of the process exit

pid_t waitpid(pid_t pid, int *result, int option);

The pid value can be as follows:

The wait() method is called by the parent process to get the exit status of any of its child processes (the first child process to exit), the number of times the parent process wait() is equal to the number of child processes.

(3) Resolve the deadly process that has arisen above

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/wait.h>

int main()
{
	pid_t pid = fork();
	assert(pid != -1);
	
	if(pid == 0)
	{	
		printf("child start\n");
		sleep(3);
		printf("child end\n");
	}
	else
	{
		wait(NULL);
		sleep(10);
	}
	return 0;
}

(4) Conclusion

  1. Although the parent process can ultimately handle the child process's deadlock by calling the wait method directly, the blocking of the wait causes the parent-child process to execute serially, which is inefficient.
  2. A wait can only handle one dead process at a time, and how many dead processes a parent process can produce is unpredictable.
  3. So the concept of signal comes out

3. Signals

(1) Signal definition

  1. Signals are special events that are predefined by the system. Signals can be generated or accepted, and the entities that produce and receive them are processes.
  2. A signal is something that happens between processes.
  3. Signals are macros, and each signal has a process specified by the system that receives the signal in the way it is processed.

(2) Modify the response of the signal

1. Default SIG_DFL
2. Ignore SIG_IGN
3. Capture (user-defined processing)

_u sighandler_t: is the type of function pointer

System calls that modify signal response:


signum: Signal type, which is the macro value of the signal

handler: A function pointer, either a user-defined function or a SIG_ DFL (default), SIG_ IGN (Ignore);

Return value: the original response of the signal is returned;

(3) Signal application

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <signal.h>

void func(int sign)
{
	printf("sign is %d\n", sign);
	printf("hello,world\n");
}
int main()
{
	signal(SIGINT, func);
	while(1)
	{
		sleep(1);
		printf("main running\n");
	
	}

	return 0;
}

Run result:

Conclusion:
During the execution of the signal function, if the signal is triggered multiple times, the system will only record once (the extra signal will be blocked), that is, the system does not maintain a message queue for the program;

4. Sending Signals

(1) System call kill

int kill(pid_t pid, int signum)

pid is the process number (greater than 0) that signals the specified process

signum: Signal type sent

Return value: Send successfully returned 0; Send failure returns -1;

(2) Copy a kill Command

Use kill pid to kill the pid process

#include <stdio.h>
#include <signal.h>
#include <string.h>

//Get the process number pid of the target process
pid_t getDesPid(int argc, char* argv[])
{
	if(argc < 1)
		return -1;
	int pid = -1;
	sscanf(argv[1], "%d", &pid);
	return pid;
}
//Send SIGTERM signal
void sendSignal(pid_t pid)
{
	if(pid <= 0)
	{
		printf("pid Wrongful\n");
		return;
	}
	kill(pid, SIGTERM);
}
int main(int argc, char* argv[])
{
	pid_t pid = getDesPid(argc, argv);

	if( pid == -1)
	{
		printf("sig or pid err\n");
		return 0;
	}
	sendSignal(pid);
	return 0;
}
  • Result:

(3) Dead processes are handled asynchronously using signals

  1. The parent process must call the wait method to handle the zombie process
  2. At the end of the child process, a signal (SIGCHLD) is automatically sent to the parent process.
  3. Parent process can call wait in signal processing function

Specific treatment: https://www.cnblogs.com/wuchanming/p/4020463.html

Keywords: Linux Process

Added by PyraX on Mon, 22 Nov 2021 23:39:27 +0200