zoukankan      html  css  js  c++  java
  • Linux System Programming 学习笔记(五) 进程管理

    1. 进程是unix系统中两个最重要的基础抽象之一(另一个是文件)

    A process is a running program
    A thread is the unit of activity inside of a process
     
    the virtualization of memory is associated with the process, the threads all share the same memory address space
     

    2. pid

    The idle process has the pid 0
    The first process that the kernel executes after booting the system, called the init process, has the pid 1
     
    默认情况下,内核规定一个最大的进程ID值:32768(16位有符号数)
    内核使用严格的线性方式为进程分配PID,如果当前所有分配的PID值最大为17,那么下一次分配的PID值为18
    进程层级:每一个进程(init进程除外)都是从另一个进程引生的
    Children normally belong to the same process groups as their parents
     

    3. 运行新进程

    In Unix, the act of loading into memory and executing a program image is separate from the act of creating a new process
    exec system call:loads a binary program into memory, replacing the previous contents of the address space, and begins execution of  the new program
    fork system call:create a new process
    to execute a new program in a new process :first a fork to create a new process, and then an exec to load a new binary into that process
     
    exec系列函数中,只有execve是系统调用,其余函数都是根据execve进行封装的C语言库函数
     
    fork系统调用之后,子进程与父进程几乎完全相同,除了以下:
    a.进程ID不同
    b.挂起的信号被清除,并不被子进程继承
    c.父进程的文件锁不被子进程继承
     
    This “fork plus exec” combination is frequent and simple:
     
    pid_t pid = fork();
    if (pid == -1) {
        fprintf(stderr, "fork error
    ");
    }
    
    /* the child */
    if (pid == 0) {
        const char* args[] = {"grep", NULL};
        int ret = execv("bin/grep", args);
        if (ret == -1) {
            fprintf(stderr, "execv error
    ");
            exit(EXIT_FAILURE);
        }
    }

    4. copy-on-write

    早期Unix中,实现fork非常简单,the kernel created copies of all internal data structures, duplicated the process's page table entries, and then performed a
    page-by-page copy of the parent's address space into the child's new address space, 这样拷贝实现无疑是费时的
     
    copy-on-write是一种减小资源复制开销的延迟策略。
    如果多个用户请求对它所拥有的资源进行读操作,资源副本的拷贝是不需要进行的,每个用户只需要操作一个指向共同资源的指针即可。只要没有用户试图修改这个资源,那么副本的拷贝开销就可以避免。如果有一个用户确实需要修改这个资源,那么直到这个时候,资源才复制一份,复制的一份资源被交给需要修改的用户,其余所有用户继续共享原初的资源
     
    在虚拟内存的具体示例中,copy-on-write是以内存页为单位进行的。
    进程的内存页首先被标记为 read-only and copy-on-write, 如果有进程需要修改这个内存页,就产生页错误,就在这时,内核复制该内存页,并且内存页的copy-on-write标记被清除。
    现代机器体系结构都硬件层面上支持copy-on-write
     

    5. exit

    当一个进程终止时,内核清除它包含的所有资源:分配的内存、打开的文件、信号量等
    结束一个程序最经典的方式不是显式调用exit,而是 "falling off the end" of the program
     
    当一个进程终止时,内核向其父进程发送 SIGCHLD 信号。默认情况下,该信号被忽略,父进程也可以调用 sigaction 捕捉该信号
     

    6. wait

    #include <sys/types.h>
    #include <sys/wait.h>
    
    /* wait() returns the pid of a terminated child or −1 on error. */
    pid_t wait (int *status);
    
    
    pid_t waitpid (pid_t pid, int *status, int options);
    当pid==-1时,waitpid等待任一子进程,等同于 wait,即 wait (&status) 等同于 waitpid (−1, &status, 0)
     

    7. system

    #define _XOPEN_SOURCE    /* if we want WEXITSTATUS, etc. */
    #include <stdlib.h>
    int system (const char *command);
    It is common to use system() to run a simple utility or shell script, often with the explicit goal of simply obtaining its return value
    If command is NULL, system() returns a nonzero value if the shell /bin/sh is available, and 0 otherwise
     
    here is a sample implementation for system():
     
    /* my_system - sync spwans and waits for the command
     * /bin/sh -c <cmd> .
     *
     * Return -1 on error of any sort, or the exit code from
     * the launched process. Does not block or ignore any signals.
     */
    
    int my_system(const char* cmd)
    {
        int status;
        pid_t pid = fork();
        if (pid == -1) {
            fprintf(stderr, "fork error
    ");
            return -1;
        } else if (pid == 0) {
            const char* argv[4];
            argv[0] = "sh";
            argv[1] = "-c";
            argv[2] = "cmd";
            argv[3] = NULL;
            execv("bin/sh", argv);
           exit(-1);
        }
        if (waitpid(pid, &status, 0) == -1) {
            return -1;
        } else if (WIFEXITED(status)) {
            return WEXITSTATUS(status);
        }
        return -1;
    }

    8. 僵尸进程

    a process that has terminated but has not yet been waited upon by its parent is called a “zombie.”
    Zombie processes continue to consume system resources, although only a small percentage
    如果一个父进程fork产生了子进程,那么该父进程就必须负责wait其子进程(回收僵尸子进程的所占资源)
    如果一个父进程在终止之前没有wait其子进程呢? 内核会视察其所有子进程,并将这些子进程挂在init进程之下(确保任何进程在任何时候都有一个父进程),init进程会周期性wait其所有子进程,这些子进程最终还是会被回收资源,而不会长期以僵尸进程形式存在
     

    9. Users and Groups

    #include <sys/types.h>
    #include <unistd.h>
    
    int setuid (uid_t uid);
    int setgid (gid_t gid);
    
    uid_t getuid (void);
    gid_t getgid (void);
    Each process is a member of a process group,Process groups that contain more than one process are generally implementing job control
     
    A command on the shell such as this one:
    /*  one process group containing three processes */
    $ cat ship-inventory.txt | grep booty | sort
     

    10. 守护进程

    A daemon is a process that runs in the background, not connecting to any controlling terminal
    通常在系统启动时开始运行,并且以root权限运行,处理系统级任务,名字后缀一般为d
     
    一个守护进程必须满足:a. 是init进程的子进程   b. 不允许与终端连接
     
  • 相关阅读:
    pl/sql可以封装代码的结构(过程,函数, 包)
    pl/sql 块结构
    Oracle 逻辑模型(数据库,用户的关系)
    Oracle 创建用户为什么要加C##
    CentOS8断电后无法正常启动
    Cannot open /var/log/sa/sa26: No such file or directory
    Centos6.6安装sysstat报错/etc/cron.d
    Oracle DBCA工具检测不到ASM磁盘组
    Redis安装
    Mysql模拟故障恢复案例过程
  • 原文地址:https://www.cnblogs.com/wwwjieo0/p/3737667.html
Copyright © 2011-2022 走看看