• Notes for Advanced Linux Programming 3. Processes


    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;

    }

  • 相关阅读:
    Metadata Lock原理5
    Seconds_Behind_Master
    Metadata Lock原理4
    MySQL Troubleshoting:Waiting on query cache mutex 腾讯数据库工程师:幕南风
    Metadata Lock原理2
    Metadata Lock原理1
    Online DDL与pt-online-schema-change
    Solaris 安装JDK
    RAID 概述
    4K Block Size的Device和 Aligned IO
  • 原文地址:https://www.cnblogs.com/forfuture1978/p/1667789.html
Copyright © 2020-2023  润新知