Document directory
- 3.1.1. Using system
- 3.1.2. Using fork and exec
3. Processes
- Each process is identified by its unique process ID
- Every process has a parent process.
- Processes are arranged in a tree, with the init process at its root
- A program can obtain the process ID with getpid () and can obtain the process ID of its parent process with the getppid ().
# Include <stdio. h>
# Include <unistd. h>
Int main ()
{
Printf ("The process ID is % d \ n", (int) getpid ());
Printf ("The parent process ID is % d \ n", (int) getppid ());
Return 0;
}
- The ps command displays the processes that are running on your system.
- You can kill a running process with the kill command.
3.1 Creating Processes3.1.1. Using system
- The system function provides an easy way to execute a command from within a program.
# Include <stdlib. h>
Int main ()
{
Int return_value;
Return_value = system ("ls-l /");
Return return_value;
}
3.1.2. Using fork and exec
- When a program callfork, a duplicate process, called the child process, is created.
- The parent process continues executing the program from the point that fork was called.
- The child process, too, executes the same program from the same place.
- The return value in the parent process is the process ID of the child.
- The return value in the child process is zero.
# Include <stdio. h>
# Include <sys/types. h>
# Include <unistd. h>
Int main ()
{
Pid_t child_pid;
Printf ("the main program process ID is % d \ n", (int) getpid ());
Child_pid = fork ();
If (child_pid! = 0 ){
Printf ("this is the parent process, with id % d \ n", (int) getpid ());
Printf ("the child's process ID is % d \ n", (int) child_pid );
}
Else
Printf ("this is the child process, with id % d \ n", (int) getpid ());
Return 0;
}
- The exec functions replace the program running in a process with another program.
- Functions that contain the letter p in their names (execvp and execlp) accept a program name.
- Functions that don't contain the p must be given the full path.
- Functions that contain the letter v in their names (execv, execvp, and execve) accept the argument list as a vector.
- Functions that contain the letter l (execl, execlp, and execle) accept the argument list as a list.
- Functions that contain the letter e in their names (execve and execle) accept an array of environment variables.
# Include <stdio. h>
# Include <stdlib. h>
# Include <sys/types. h>
# Include <unistd. h>
/* Spawn a child process running a new program. PROGRAM is the name of the program to run; the path will be searched for this program. ARG_LIST is a NULL-terminated list of character strings to be passed as the program's argument list. returns the process ID of the spawned process. */
Int spawn (char * program, char ** arg_list)
{
Pid_t child_pid;
/* Duplicate this process .*/
Child_pid = fork ();
If (child_pid! = 0)
/* This is the parent process .*/
Return child_pid;
Else {
/* Now execute PROGRAM, searching for it in the path .*/
Execvp (program, arg_list );
/* The execvp function returns only if an error occurs .*/
Fprintf (stderr, "an error occurred in execvp \ n ");
Abort ();
}
}
Int main ()
{
/* The argument list to pass to the "ls" command .*/
Char * arg_list [] = {
"Ls",/* argv [0], the name of the program .*/
"-L ",
"/",
NULL/* The argument list must end with a NULL .*/
};
/* Spawn a child process running the "ls" command. Ignore the returned child process ID .*/
Spawn ("ls", arg_list );
Printf ("done with main program \ n ");
Return 0;
}
3.2 Signals
- A signal is a special message sent to a process.
- When a process has es a signal, it processes the signal immediately, without finishing the current function or even the current line of code
- The Linux system sends signals to processes in response to specific conditions.
- SIGBUS (bus error ),
- SIGSEGV (segmentation violation ),
- SIGFPE (floating point exception)
- A process may also send a signal to another process.
- End another process by sending it a SIGTERM or SIGKILL signal
- Send a command to a running program. Two "userdefined" signals are reserved for this purpose: SIGUSR1 and SIGUSR2.
- The sigaction function can be used to set a signal disposition.
- SIG_DFL, which specifies the default disposition for the signal.
- SIG_IGN, which specifies that the signal shoshould be ignored.
- A pointer to a signal-handler function.
- Because signals are asynchronous, you should avoid should Ming any I/O operations or calling most library and system functions from signal handlers.
- A signal handler shocould perform the minimum work necessary to respond to the signal.
- It is possible for a signal handler to be interrupted by the delivery of another signal.
- If you use a global variable to flag a signal from a signal-handler function, it shocould be of the special type sig_atomic_t.
# Include <stdio. h>
# Include <signal. h>
# Include <string. h>
# Include <sys/types. h>
# Include <unistd. h>
Sig_atomic_t sigusr1_count = 0;
Void handler (int signal_number)
{
++ Sigusr0000count;
}
Int main (int argc, char * argv [])
{
Printf ("the process ID is % d \ n", (int) getpid ());
Struct sigaction sa;
Memset (& sa, 0, sizeof (sa ));
Sa. sa_handler = & handler;
Sigaction (SIGUSR1, & sa, NULL );
Int I = 0;
While (I <100)
{
Sleep (1 );
I ++;
}
Printf ("SIGUSR was raised % d times \ n", sigusr0000count );
Return 0;
}
- Compile the above code to program sigusr1
Gcc-o sigusr1 sigusr1.c
[Liuchao @ localhost Signal] $./sigusr1
The process ID is 3401
- From another terminal, use ps to see the pid of sigusr1
[Liuchao @ localhost ~] $ Ps-
PID TTY TIME CMD
3401 pts/1 00:00:00 sigusr1
3403 pts/3 00:00:00 ps
- Send parameters sigusr1 signals to the process id.
[Liuchao @ localhost ~] $ Kill-s SIGUSR1 3401
[Liuchao @ localhost ~] $ Kill-s SIGUSR1 3401
[Liuchao @ localhost ~] $ Kill-s SIGUSR1 3401
[Liuchao @ localhost ~] $ Kill-s SIGUSR1 3401
[Liuchao @ localhost ~] $ Kill-s SIGUSR1 3401
- After the process finish.
[Liuchao @ localhost Signal] $./sigusr1
The process ID is 3401
SIGUSR was raised 5 times
3.3 Process Termination
- A process terminates in one of two ways
- The executing program callthe exit function, or the program's main function returns.
- A process may also terminate abnormally, in response to a signal.
- SIGINT for ctrl + C
- SIGTERM for kill command
- SIGABRT for abort function
- SIGKILL ends a process immediately and cannot be blocked or handled by a program.
- Any of these signals can be sent using the kill command
% Kill-KILL pid
- To send a signal from a program, use the kill function.
Kill (child_pid, SIGTERM );
- Wait blocks the calling process until one of its child processes exits (or an error occurs ).
- The waitpid function can be used to wait for a specific child process to exit instead of any child process.
- The wait3 function returns CPU usage statistics about the exiting child process
- Wait4 function allows you to specify additional options about which processes to wait.
Int main ()
{
Int child_status;
/* The argument list to pass to the "ls" command .*/
Char * arg_list [] = {
"Ls",/* argv [0], the name of the program .*/
"-L ",
"/",
NULL/* The argument list must end with a NULL .*/
};
/* Spawn a child process running the "ls" command. Ignore the returned child process ID .*/
Spawn ("ls", arg_list );
/* Wait for the child process to complete .*/
Wait (& child_status );
If (WIFEXITED (child_status ))
Printf ("the child process exited normally, with exit code % d \ n", WEXITSTATUS (child_status ));
Else
Printf ("the child process exited abnormally \ n ");
Return 0;
}
- A zombie process is a process that has terminated but has not been cleaned up yet.
- It is the responsibility of the parent process to clean up its zombie children with wait function.
- If the parent does not clean up its children, they stay around in the system as zombie processes.
# Include <stdlib. h>
# Include <sys/types. h>
# Include <unistd. h>
Int main ()
{
Pid_t child_pid;
/* Create a child process .*/
Child_pid = fork ();
If (child_pid> 0 ){
/* This is the parent process. Sleep for a minute .*/
Sleep (60 );
}
Else {
/* This is the child process. Exit immediately .*/
Exit (0 );
}
Return 0;
}
- % Ps-e-o pid, ppid, stat, cmd
3824 2888 S +./zombie
3825 3824 Z + [zombie] <defunct>
- When a program exits, its children are inherited by a special process, the init program which automatically cleans up any zombie child processes that it inherits.
- When a child process terminates, Linux sends the parent process the SIGCHLD signal.
- An easy way to clean up child processes is by handling SIGCHLD.
# Include <signal. h>
# Include <string. h>
# Include <sys/types. h>
# Include <sys/wait. h>
Sig_atomic_t child_exit_status;
Void clean_up_child_process (int signal_number)
{
/* Clean up the child process .*/
Int status;
Wait (& status );
/* Store its exit status in a global variable .*/
Child_exit_status = status;
}
Int main ()
{
/* Handle SIGCHLD by calling clean_up_child_process .*/
Struct sigaction sigchld_action;
Memset (& sigchld_action, 0, sizeof (sigchld_action ));
Sigchld_action.sa_handler = & clean_up_child_process;
Sigaction (SIGCHLD, & sigchld_action, NULL );
/* Now do things, including forking a child process .*/
/*...*/
Return 0;
}