Notes for Advanced Linux Programming - 3. Processes

来源:互联网 发布:php location 编辑:程序博客网 时间:2024/06/06 20:43

 

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 atits root
  • A program can obtain the process ID with getpid() and canobtain 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 onyour 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 commandfrom 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 thechild process, is created.
  • The parent process continues executing the program fromthe point that fork was called.
  • The child process, too, executes the same program from thesame place.
  • The return value in the parent process is the process IDof 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, withid %d/n”, (int) getpid ());

    return 0;

}

  • The exec functions replace the program running in aprocess with another program.
  • Functions that contain the letter p in their names (execvpand execlp) accept a program name.
  • Functions that don’t contain the p must be given the fullpath.
  • 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 (execveand 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 newprogram. PROGRAM is the name of the program to run; the path will besearched for this program. ARG_LIST is a NULL-terminated list ofcharacter 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 signalimmediately, without finishing the current function or even the current line ofcode
  • The Linux system sends signals to processes in response tospecific 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 SIGKILLsignal
  • Send a command to a running program.Two “userdefined” signalsare reserved for this purpose: SIGUSR1 and SIGUSR2.
  • The sigaction function can be used to set a signaldisposition.
  • SIG_DFL, which specifies the default disposition for thesignal.
  • SIG_IGN, which specifies that the signal should beignored.
  • A pointer to a signal-handler function.
  • Because signals are asynchronous, you should avoidperforming any I/O operations or calling most library and system functions fromsignal handlers.
  • A signal handler should perform the minimum work necessaryto respond to the signal.
  • It is possible for a signal handler to be interrupted bythe delivery of another signal.
  • If you use a global variable to flag a signal from asignal-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

  PIDTTY          TIME CMD

 3401pts/1    00:00:00 sigusr1

 3403pts/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 theprogram’s main function returns.
  • A process may also terminate abnormally, in response to asignal.
  • SIGINT for ctrl + C
  • SIGTERM for kill command
  • SIGABRT for abort function
  • SIGKILL ends a process immediately and cannot be blockedor 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 childprocesses exits (or an error occurs).
  • The waitpid function can be used to wait for a specificchild process to exit instead of any child process.
  • The wait3 function returns CPU usage statistics about theexiting child process
  • wait4 function allows you to specify additional optionsabout 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 exitednormally, with exit code %d/n”, WEXITSTATUS (child_status));

    else

        printf (“the child process exitedabnormally/n”);

    return 0;

}

  • A zombie process is a process that has terminated but hasnot been cleaned up yet.
  • It is the responsibility of the parent process to clean upits zombie children with wait function.
  • If the parent does not clean up its children, they stayaround 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 aspecial process, the init program which automatically cleans up any zombiechild processes that it inherits.
  • When a child process terminates, Linux sends the parentprocess the SIGCHLD signal.
  • An easy way to clean up child processes is by handlingSIGCHLD.

#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 (intsignal_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;

}

 

原创粉丝点击