• 【linux】初识进程


    本节我们来初步认识一下进程,有些要深入研究的知识,等到后面进程部分讲解


    初识进程

    1、什么是进程

    一个运行起来(加载到内存)的程序叫做进程
    在内存中的程序叫做进程(这样说也是正确的)

    这也就是我们前面为什么说要把一个程序加载到内存里面

    当然,如果是没接触过进程的人可能只是知道上面语句的意思,但是不理解。不着急,下面会一步步解释的

    首先我们知道,程序的本质:就是文件,而文件存放在磁盘中
    我们之前都是一次执行一个程序,也就是把一个程序加载到内存中。但是,如果有多个程序共同加载到内存中呢?
    每个程序在内存中对应的存放位置,什么时候被执行,什么时候执行结束销毁?等等都要被操作系统所管理,既然是管理,那么就要遵循管理的方法先描述,后组织

    在这里插入图片描述
    所以,要进行管理进程,那么就要遵循先描述,后组织的管理方法

    因为要先描述,所以我们可以像上一节讲计算机内部结构一样,把所有文件的相同数据/属性都整理到一起,统一放到struct或者class(结构体或者类)当中。而内存中的这个结构体就叫做PCB,也称之为进程控制块(Linux操作系统下的PCB是:task struct

    在这里插入图片描述
    在这里插入图片描述

    也就是说:操作系统不是对可执行程序直接操作的,而是对进程的PCB(进程控制块)进行操作。在PCB内部,通过优先级的方式,找到操作系统需要的属性/数据之后,PCB将对应的可执行程序的代码交给操作系统执行。当PCB的对象内部有属性死亡之后,先释放可执行程序中的代码,然后再释放掉PCB的对象(也就是释放链表中的节点),此时,进程就被释放掉了

    小结:

    先描述:构建PCB(进程控制块)
    在组织:对进程进行管理,变成了对进程对应的PCB进行相关的管理(对进程的管理 -> 对链表的增删查改)

    在这里插入图片描述

    2、见见进程

    windows下的进程:

    打开任务管理器(ctrl+alt+del)
    在这里插入图片描述
    这些都是电脑中正在运行的进程

    linux下的进程:
    makefile:

    myproc:myproc.c
    	gcc -o myproc myproc.c
    .PHONY:clean
    clean:
    	rm -f myproc
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    ps ajx

    ps ajx :显示所有进程

    在这里插入图片描述

    ps sjx | head -1 && ps ajx | grep "myproc"
    
    
    • 1
    • 2

    在这里插入图片描述

    kill -9 +进程id

    kill -9 +进程id :终止对应的进程(有的进程ctrl +c/+d不能停止)

    小结:

    进程在调度运行的时候,进程就具有动态属性

    kill -l

    kill -l : 查看对应的信号编号

    在这里插入图片描述

    见见与进程有关的系统调用

    getpid

    myporc.c

    while(1)
        {
            printf("我是一个进程!, 我的ID是: %d", getpid());
            sleep(1);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    另一种查看进程的方式:

    /proc——==进程的信息可以通过 /proc 系统文件夹查看==
    
    • 1

    在这里插入图片描述这些数字开头的就是对应的进程的PID

    在进程执行的期间,即便是可执行程序被删除了,进程也不会停止,会一直执行:
    在这里插入图片描述
    在这里插入图片描述

    getppid
    while(1)
        {
            printf("我是一个进程!, 我的ID是: %d, 父进程pid: %d\n", getpid(), getppid());
            sleep(1);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    小结:

    命令行上启动的进程,一般它的父进程没有特殊情况的话,就是bash!

    我们启动linux就会自动产生一个bash,以及对应的pid。我们再linux下面执行的ls等命令或者./a.out等操作都是父进程生成的子进程来进行操作的

    在这里插入图片描述

    这里就引出两个问题来了:

    1、父进程怎么创建子进程的?
    2、子进程是怎么运行起来的?

    这两个问题现在解释清楚很难,我们后面会解释

    现在就先来看看父进程如何创建子进程的

    创建子进程

    这里要用到fork()函数,我们可以通过man fork来查看该函数怎么使用
    在这里插入图片描述
    在底行模式输入:/return val查看fork返回值
    在这里插入图片描述
    翻译过来就是:

    如果fork调用成功,那么把子进程的pid返回给父进程,把0返回给子进程;
    如果调用失败,-1返回父进程,没有子进程生成

    注意:也就是说,fork函数有两个返回值!!!

    pid_t id = fork();
    while(1)
    {
        printf("子进程, pid: %d, ppid: %d, id: %d\n", getpid(), getppid(), id);
        sleep(1);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述
    看起来好像是这样,与文案的描述一样,但是:
    同一个变量id, 在后续不会被修改的情况下,竟然有不同的内容!,并且下面还要更奇怪的现象

    myproc.c

    #include 
    #include 
    #include 
    int main()
    {
        // 创建子进程 -- fork是一个函数 -- 函数执行前: 只有一个父进程 -- 函数执行后: 父进程+子进程
        pid_t id = fork();
        if(id == 0)
        {
            //子进程
            while(1)
            {
                printf("子进程, pid: %d, ppid: %d, id: %d\n", getpid(), getppid(), id);
                sleep(1);
            }
        }
        else if(id > 0)
        {
            // parent
            while(1)
            {
                printf("父进程, pid: %d, ppid: %d, id: %d\n", getpid(), getppid(), id);
                sleep(2);
            }
        }
        else
        {
        }
        // 同一个变量id, 在后续不会被修改的情况下,竟然有不同的内容!
        //printf("我是一个进程, pid: %d, ppid: %d, id: %d\n", getpid(), getppid(), id);
        sleep(2);
    //    while(1)
    //    {
    //        printf("我是一个进程!, 我的ID是: %d, 父进程pid: %d\n", getpid(), getppid());
    //        sleep(1);
    //        //int a = 1/0;
    //    }
    //    return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    在这里插入图片描述

    这里,if和else if语句竟然同时执行了!并且,两个while死循环也同时执行了!!!(这里也解释不清楚,等后面学了进程地址空间再来解释)
    这在C/C++语言根本不敢想象

    原因:

    1、fork()之后,会有父进程+子进程两个程序在执行后续代码
    2、fork()后续的代码,会被父子进程共享。通过返回值不同,父子进程执行后续共享代码的一部分
    。数据各自开辟空间,私有一份(采用写时拷贝)。

    总结
    可以看到,系统与我们前面学习的语言区别还是很大的,光一个fork函数就不能通过语言来解释清楚,所以不能局限于语言,其他各个方面也要学好!

  • 相关阅读:
    leecode#只出现一次数字#环形链表
    [LeetCode周赛复盘] 第 299 场周赛20220626
    STP选举
    IINA for Mac v1.3.5 音视频软件 安装教程(保姆级)
    前端三剑客—HTML
    【.net core】解决无法下载wgt文件问题
    【Redis】List的常用命令以及常用场景
    1314. 矩阵区域和-矩阵前缀和算法
    Swoole Compiler 加密PHP源代码(简版)
    mac gdb调试失败解决
  • 原文地址:https://blog.csdn.net/kdjjdjdjjejje128/article/details/127785733