进程概念

基本概念

       首先,进程是什么?我们见过的最多的解释就是进程是程序的一个执行实例,正在执行的程序等。但从根本上来看,进程实际上就是正在运行的程序所对应的一套代码以及这个程序所拥有的资源

       对于操作系统来说,要管理一个对象,就要先对这个对象进行描述,再对这个对象进行组织。对于进程,就是用 PCB 来描述的。PCB(process control block)其实就是一个叫做程序控制块的数据结构,可以理解为进程属性的集合。不同的操作系统下的 PCB 是不同的,在 linux 下的 PCB 叫做 task_struct,因为这个结构中包含的东西很多,在这里列举几个比较重要的信息来了解一下 task_struct 中到底存放了哪些信息:

  • 标识符:进程id,描述本进程的唯一标识符,用来区别其他进程
  • 状态:标识进程当前的状态,退出代码,退出信号等
  • 优先级:相对于其他进程的优先级
  • 程序计数器:程序中即将被执行的下一条指令的地址
  • 一组内存指针:进程对应的代码和代码依赖的数据的位置的指针,还有和其他进程共享的内存块的指针
  • 上下文数据:保存了该进程上次在CPU上执行的现场,也就是CPU中的各种寄存器中的数据
  • I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表
  • 记账信息:可能包含了处理器的时间总和,使用的时钟数总和,时间限制,记账号等
  • 其他信息

查看进程

       在linux的根目录下,有一个 proc 目录,里面存放着所有进程的信息,我们可以通过这个文件来查看进程的一些信息

       大多数进程通过 top 和 ps 命令也可以查看到进程的信息,top 更像是Windows下的任务管理器

       使用 ps 命令可以筛选出想要查看的进程

       还可以通过系统调用来获取进程的 pid 和该进程的父进程的 pid ---- ppid

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>


int main()
{
    printf("pid: %d\n", getpid());
    printf("ppid: %d\n", getppid());
    return 0;
}

进程创建

       通常我们执行一个程序,就是创建了一个进程,而一个现有的进程,可以通过 fork 函数,创建一个新的进程,这个新的进程就叫做原有进程的子进程,此时原有进程就成了这个新进程的父进程。父进程创建子进程的过程,是以父进程为模板,把父进程的 PCB 复制过来稍加修改,内存指针基本相同,上下文也相同,父子进程执行的同一份代码,再加上上下文也相同,因此,父子进程都要从 fork 执行完毕后的位置继续执行下去,但父子进程之间的数据是独享的。而对于 fork 的返回值,父进程返回子进程的 pid ,子进程返回 0,fork 失败时返回 -1。通过代码来看一下:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    int ret = fork();
    if(ret < 0) {
        perror("fork failed!\n");
    } else if(ret > 0) {
        printf("I am father: %d, ret: %d\n", getppid(), ret);
    } else {
        printf("I am child: %d, ret: %d\n", getpid(), ret);
    }
    sleep(1);
    return 0;
}

      通过执行结果可以看到,父进程返回了子进程的 pid,子进程返回了0

fork 调用失败的原因

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

进程状态

       进程状态反映的是进程执行过程的变化,这些状态随着进程的执行和外界条件的变化而转换。在五态模型中,进程的状态被分为以下五种:

  • R运行状态(running):并不意味着进程一定在运行中,它表明进程是在运行中或者是在运行队列里
  • S睡眠状态(sleeping):意味着进程在等待事件完成,这里的睡眠有时候也叫做可中断睡眠(interruptible sleep)
  • D磁盘休眠状态(Disk sleep):有时也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束
  • T停止状态(stopped):可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让程序继续运行
  • X死亡状态(dead):这个状态只是一个返回状态,在任务列表中是看不到这个状态的

进程状态的转换

       这里以T/R状态转换为例演示进程状态的转换,使用如下的代码,让我们可以看到进程的状态

int main()
{
    while(1);
    return 0;
}

       运行后可以看到进程此时处于运行状态

       使用 kill -SIGSTOP pid 命令使进程变为停止状态

       使用 kill -SIGCONT pid 命令是进程重新变回运行状态

僵尸进程

       首先让我们通过代码来认识一下僵尸进程

int main()
{
    pid_t pid = fork();
    if(pid < 0) {
        perror("fork failed!\n");
        return 1;
    } else if(pid == 0) {
        printf("child is sleep: %d\n", getpid());
        sleep(5);
        exit(1);
    } else {
        printf("father is sleeping : %d\n", getpid());
        sleep(30);
    }
    return 0;
}

       当程序执行后,查看进程状态,可以看到有一个状态为 Z(zombie) 的进程,这就是僵尸进程

       僵尸进程其实就是子进程向父进程汇报执行结果的一种机制,在父进程查看这个结果之前,这个结果不应该被释放,就保存在子进程的PCB中。如果父进程能够及时读取子进程的返回结果,僵尸进程也就不会存在了。

       那么僵尸进程可以杀死吗?我们来试试,用 kill -9 pid 杀死子进程,再次查看,发现子进程依然存在,

       我们再使用 kill -9 pid 杀死它的父进程,这时就会发现僵尸进程没有了。

       这是因为当父进程提前退出后,子进程没有人管了,这时的子进程就称为 "孤儿进程",孤儿进程会被 1 号 init 进程领养,那么 1 号进程就会查看并回收孤儿进程的资源,从而释放子进程。注意:孤儿进程并不是一种进程状态。

僵尸进程的危害

       在父进程读取并回收子进程的资源之前,子进程的退出状态必须一直被维护下去,维护退出状态本身就是用数据来维护,也属于进程基本信息,所以是保存在进程的 PCB 中,换句话说,僵尸进程一直存在,PCB 就不会被释放。那么假如父进程创建了多个子进程,并且都不去回收,那么这些子进程的 PCB 将都不被释放,造成资源泄露。

进程优先级

       进程优先级指 cpu 资源分配的先后顺序,就是指进程的优先权,优先权高的进程有优先执行的权利。通过调整进程的优先级,可以控制某个进程执行占有 cpu 的能力,可以让优先级更高的重要进程优先执行。在 linux 下,可以通过 ls -l 命令查看有关进程优先级的信息:

       在这里我们可以看到 PRI 和 NI 两个值,PRI 表示当前进程的优先级,其值越小,进程的优先级越高;NI 表示的是该进程的 nice 值,nice 是进程优先级的修正值,并不是进程的优先级,PRI 是通过系统默认的优先级加上 nice 值最终得出来的,因此我们修改进程的优先级就是通过修改 nice 值来完成的。nice 值的取值为 -20 ~ 19,一共 40 个级别,当 nice 值为正时,表示该进程的优先级降低。

修改进程的优先级

进程启动前调整:nice

       在调整前先来看看这个进程的默认优先级:

       再来看看该进程调整后的优先级:

调整已存在的进程:renice

       先看看已存在进程的 pid 和优先级:

       使用 renice 指令修改已存在的进程优先级,并查看:

用 top 命令修改已存在的进程 nice:

      top 命令类似于我们在 Windows 下查看任务管理器,输入 top 命令后,可看到:

      进入 top 后按 r,接着输入进程的 pid,再输入 nice 值,就可以修改指定进程的优先级了。

其他概念

  • 竞争性:系统资源进程数目众多,而cpu资源有限,大多数情况下只有一个,所以进程之间是具有竞争性的。为了合理竞争资源,高效完成任务,于是便有了进程优先级
  • 独立性:多进程同时运行,各自的资源独享,运行期间互不干扰
  • 并行:多个进程在多个 cpu 下同时运行,这称之为并行
  • 并发:多个进程在一个 cpu 下采用进程切换的方式,在一个时间段内,让多个进程都得以推进,称之为并发。因为 cpu 调度快,在宏观角度来看非常像并行

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值