您的位置:首页 > 运维架构 > Linux

Notes for Advanced Linux Programming - 3. Processes

2010-02-11 12:56 513 查看

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 Processes

3.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 calls fork, 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 receives 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 should be
ignored.


A pointer to a signal-handler function.

Because signals are asynchronous, you should avoid
performing any I/O operations or calling most library and system functions from
signal handlers.


A signal handler should 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 should 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)
{

++sigusr1_count;
}
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", sigusr1_count);

return 0;
}


Compile the above code to program sigusr1

gcc -o sigusr1 sigusr1.c

Run the program

[liuchao@localhost Signal]$ ./sigusr1
the process ID is 3401

From another terminal, use ps to see the pid of sigusr1

[liuchao@localhost ~]$ ps -a
PID
TTY TIME CMD
3401
pts/1 00:00:00 sigusr1
3403
pts/3 00:00:00 ps

Send many 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 calls the 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 for.


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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: