zoukankan      html  css  js  c++  java
  • 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;

    }

  • 相关阅读:
    June 26th 2017 Week 26th Monday
    June 25th 2017 Week 26th Sunday
    June 24th 2017 Week 25th Saturday
    June 23rd 2017 Week 25th Friday
    June 22nd 2017 Week 25th Thursday
    2018最佳网页设计:就是要你灵感爆棚!!!
    图片素材类Web原型制作分享-Pexels
    想要打动HR的心,UX设计师求职信究竟应该怎么写?
    【UXPA大赛企业专访】Mockplus:“设计替代开发”将成为现实
    2018年最好的医疗网站设计及配色赏析
  • 原文地址:https://www.cnblogs.com/forfuture1978/p/1667789.html
Copyright © 2011-2022 走看看