【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

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

ps ajx

ps ajx :显示所有进程

在这里插入图片描述

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

在这里插入图片描述

kill -9 +进程id

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

小结:

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

kill -l

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

在这里插入图片描述

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

getpid

myporc.c

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

在这里插入图片描述

另一种查看进程的方式:

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

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

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

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

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

小结:

命令行上启动的进程,一般它的父进程没有特殊情况的话,就是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);
}

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

myproc.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
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;
}

在这里插入图片描述

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

原因:

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

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值