Linux学习之:进程的控制

创建一个进程都创建了哪些内容

1.进程的PCB块
2.进程的虚拟地址空间mm_struct
3.进程的页表
这三个一起才算完成了进程的创建!

为什么要有地址空间?(重要!)

在这里插入图片描述
Linux学习之:进程的控制_第1张图片
在这里插入图片描述

fork()创建子进程

进程调用fork,当控制转移到内核中的fork代码后,
内核做:
1.分配新的内存块和内核数据结构给子进程
2.将父进程部分数据结构内容拷贝至子进程
3.添加子进程到系统进程列表当中
4.fork返回,开始调度器调度

通常,父子代码共享,父子再不写入时,数据也是共享的

fork()返回值

子进程返回0,
父进程返回的是子进程的pid

写时拷贝

通常,父子代码共享,父子再不写入时,数据也是共享的,当任意(是任意一方!)一方试图写入,便以写时拷贝的方式各自一份副本
因此发生写时拷贝后表面上看父子进程还是指向同一个地址同一个空间,其实子进程的地址已经被页表映射到其他地方去了!!Linux学习之:进程的控制_第2张图片

fork常规用法

1.一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
2.一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数

fork调用失败的原因

1.系统中有太多的进程
2.实际用户的进程数超过了限制

Linux学习之:进程的控制_第3张图片

进程终止

进程退出场景

代码运行完毕,结果正确
代码运行完毕,结果不正确
代码异常终止

进程常见退出方法

正常终止(可以通过 echo $? 查看进程退出码):
1.从main返回
2.调用exit
3._exit

Linux学习之:进程的控制_第4张图片

exit()与_exit()

Linux学习之:进程的控制_第5张图片

进程等待

进程等待必要性(重要!)

首先需要了解进程退出OS做了些什么
在这里插入图片描述
Linux学习之:进程的控制_第6张图片

进程等待的方法

Linux学习之:进程的控制_第7张图片

阻塞的本质

在这里插入图片描述

status状态码(重要!!!)

Linux学习之:进程的控制_第8张图片
Linux学习之:进程的控制_第9张图片

宏观理解waitpid

Linux学习之:进程的控制_第10张图片

进程程序替换(重要!)

替换原理

Linux学习之:进程的控制_第11张图片
Linux学习之:进程的控制_第12张图片

如何替换?

Linux学习之:进程的控制_第13张图片

替换函数

Linux学习之:进程的控制_第14张图片
Linux学习之:进程的控制_第15张图片

程序替换其实只有一个系统调用其他的都是进行封装过的

Linux学习之:进程的控制_第16张图片

做一个简易的shell

主要是为了理解我们在命令行创建的进程都是bash的子进程,bash也是利用程序替换的方法让作为子进程的我们去执行自己的代码(这层理解很重要!!!)

Linux学习之:进程的控制_第17张图片

Linux学习之:进程的控制_第18张图片

#include 
#include 
#include 
#include 
#include 

#define NUM 128
#define CMD_NUM 64

int main()
{
    char command[NUM];
    for( ; ; ){
        char *argv[CMD_NUM] = { NULL };
        //1. 打印提示符
        command[0] = 0; //用这种方式,可以做到O(1)时间复杂度,清空字符串
        printf("[who@myhostname mydir]# ");
        fflush(stdout);
        //2. 获取命令字符串
        fgets(command, NUM, stdin);
        command[strlen(command) - 1] = '\0'; //"ls\n\0"
        //printf("echo: %s\n", command);

        //"ls -a -b -c\0";
        //3. 解析命令字符串, char *argv[];
        //strtok();
        const char *sep = " ";
        argv[0] = strtok(command, sep);
        int i = 1;
        while(argv[i] = strtok(NULL, sep)){
            i++;
        }

        //4.检测命令是否是需要shell本身执行的,内建命令
        if(strcmp(argv[0], "cd") == 0){
            if(argv[1] != NULL) chdir(argv[1]);
            continue;
        }

        //5. 执行第三方命令
        if(fork() == 0){
            //child
            execvp(argv[0], argv);
            exit(1);
        }

        int status = 0;
        waitpid(-1, &status, 0);
        printf("exit code: %d\n", (status >> 8)&0xFF);

        //for(i=0; argv[i]; i++){
        //    printf("argv[%d]: %s\n", i, argv[i]);
        //}
    }
}

你可能感兴趣的:(linux,学习)