进程的概念及相关练习

一、进程的概念

1、进程
进程就是PCB,是一个运行中程序的描述,通过描述信息中的内存指针能够找到内存中运行的程序代码以及数据,并且通过上下文数据可以保存程序调度切换时正在处理的数据,以及通过程序计数器保存进程切换时程序即将执行的下一步指令,等等…通过这些描述信息实现控制一个程序的运行,因此对于操作系统 来说进程就是PCB。

描述信息:内存指针、上下文数据、程序计数器、标识符、进程状态、优先级、记账信息、IO信息

2、CPU的分时机制
进程在操作系统中调度是切换运行的,每个进程都有一个CPU的时间片(一个进程在CPU上运行的时间段),在CPU上时间片运行完毕后切换到下一个进程。

3、进程的查看
查看进程:ps

  • ps -ef 查看的信息较为粗略(-e表示查看所有的,f表示以 树状的形式查看)
  • ps -aux 查看的信息比较详细
  • 快速的定位查看信息:ps -ef | grep [文件名]

4、进程状态
运行:正在运行的进程
就绪:拿到时间片就能运行,处于等待的状态
阻塞:没有在运行

在linux下的进程状态:

  • 运行状态R(Runing):包括正在运行的以及拿到时间片就能运行的
  • 可中断休眠状态S(sleeping):进程在等待时间完成
  • 不可中断休眠状态D(Disk sleep):通常会等待IO的结束
  • 停止状态T(stopped):通过发送SISTOP信号来停止进程,可以发送SICONT信号来开始进程
  • 僵死状态Z(zombie):进程已经退出,但是资源没有完全释放

僵死状态
僵尸进程:处于僵死态的进程(进程已经退出,但是资源没有完全释放)

僵尸进程的产生原因:
子进程先于父进程退出,退出后,为了保存自身的退出原因(返回值),因此资源没有完全被释放,操作系统这时候通知父进程获取子进程的退出状态,并允许操作系统释放资源,但是若父进程没有关注这个退出状态,则子进程虽然退出了,但是资源没有完全被释放,处于僵死状态,称为僵尸进程。

僵尸进程的危害:资源泄漏。

孤儿进程
父进程先于子进程退出,子进程就成为了孤儿进程,运行在系统后台,并且被1号init进程收养。此时孤儿进程退出后不会称为僵尸进程,资源立即被回收。

杀死进程:kill + 进程id(只能杀死运行或休眠中的进程)
杀死一个停止的进程:kill -9 + 进程id

5>创建进程
调用fork()来创建一个父进程
创建子进程:pid_t pid = fork();

4、进程优先级
决定进程cpu调度优先权的级别==>让操作系统运行的更加良好
批处理程序/交互式程序
cpu密集型程序/io密集型程序

5、环境变量
定义:用于存储系统运行环境参数的变量
作用:是系统的参数配置更加灵活
额外作用:向进程传递参数

操作命令:

  • env :查看所有环境变量
  • echo:打印指定环境变量的内容
  • set :查看shell中的所有变量信息(不只有环境变量)
  • export:将一个变量设置为一个环境变量
  • unset:删除一个变量(包含环境变量)

代码中对环境变量的操作

  • main函数第三个参数–保存所有的环境变量
  • extern char** environ; 全局变量
  • char *getenv(const char *name) 通过环境变量名称获取内容

6、程序地址空间

内存地址:内存区域的编号
每个进程都有一个自己的进程地址空间
创建子进程:父子进程代码共享,数据都有
进程中所访问到的地址实际上是一个虚拟地址

程序地址空间->进程地址空间->虚拟地址空间

虚拟地址空间:实际上是一个内存描述符
通过一个结构体描述出一块完整的连续的线性的地址空间
size/code_start/code_end/data_start/data_end
mm_struct结构体—内存描述符

  • 直接使用物理内存的缺陷
  • 内存使用率低
  • 缺乏内存访问控制

解决方法:在进程中建立虚拟地址,实现离散式存储
操作系统通过虚拟地址空间向进程描述一个完整的连续的地址空间,供进程使用,但是在物理内存中进程数据的存储采用离散式存储(提高内存使用率)并且使用页表映射虚拟地址与物理地址之间的映射关系,并且在页表中可以实现内存才能访问控制(标志位表示内存的访问权限)

页表:在物理地址与虚拟地址之间建立映射关系

如何通过虚拟地址得到物理地址

  • 分段式内存管理
    内存地址的组成:段号+段内偏移
    优点:对程序的内存管理比较友好

  • 分页式内存管理
    虚拟地址的组成:页号+页内偏移

  • 段页式内存管理
    虚拟地址组成:段号+段内页号+页内偏移

二、进程的调度算法.

调度算法是指:根据系统资源分配策略所规定的资源分配算法。对于不同的系统或系统目标,通常采用不同的调度算法,常见的调度算法有以下几种:

  1. 先来先服务调度算法(FCFS,first come first served):谁第一个排队,谁就先被执行,在它执行过程中,不会中断它;
  2. 短作业优先调度算法(SJF,shortest job first):对预计执行时间短的进程有限分配处理机,通常后来的短进程不会抢先正在执行的进程;对长进程非常不利,可能长时间得不到执行。
  3. 最高响应比优先法(HRRN,highest response radio next):对于FCFS和SJF的平衡,FCFS方式只考虑每个作业的等待时间而未考虑执行时间的长短,而SJF只考虑了执行时间而未考虑等待时间的长短,因此两种算法在某种极端的情况下会带来某些不便。HRRN通过综合这两种情况算出响应比R,根据响应比完成调度。优点:长作业也有机会投入运行,缺点:每次调度前要计算响应比。
  4. 时间片轮转法(RR,Round-Robin):采用剥夺方式,每个进程被分配一个时间段,按照在队列中的顺序交替执行;不利于处理紧急作业。
  5. 多级反馈队列(multilevel feedback queue): UNIX使用这种调度算法;进程在进入待调度的队列等待时,首先进入优先级最高的Q1中等待;首先调度优先级高的队列中的进程。若高优先级队列中已经没有调度的进程,则调度次优先级队列的进程;同一队列中的各个进程按照时间片轮转调度;在低优先级队列中的进程在运行时,又有新到达的作业,那么在运行完这个时间片后,CPU马上分配给新到达的作业(剥夺)。

三、 task_struct结构体中的各个字段的含义

在Linux中描述进程的结构体叫做task_struct, 它包含的字段有以下内容:

  1. 标识符:描述本进程的唯一标识符,用来区别其他进程;
  2. 状态:任务状态,退出代码,退出信号等;
  3. 优先级:相对于其他进程的优先级;
  4. 程序计数器:程序中即将被执行的下一条指令地址;
  5. 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
  6. 上下文数据:进程执行时处理器的寄存器中的数据
  7. I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表
  8. 记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等;
  9. 其他信息

四、使用代码模拟实现僵尸进程, 孤儿进程的场景

僵尸进程:处于僵死态的进程(进程已经退出,但是资源没有完全释放)

僵尸进程的产生原因:
子进程先于父进程退出,退出后,为了保存自身的退出原因(返回值),因此资源没有完全被释放,操作系统这时候通知父进程获取子进程的退出状态,并允许操作系统释放资源,但是若父进程没有关注这个退出状态,则子进程虽然退出了,但是资源没有完全被释放,处于僵死状态,称为僵尸进程。

僵尸进程的代码演示如下:

#include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 
  5 int main()
  6 {
  7     printf("*******\n");
  8     pid_t pid = fork();
  9     if(pid<0)
 10     {
 11         printf("fork error!--%d\n",getpid());//getpid()是获取进程的pid,没有参数
 12         return -1;
 13     }
 14     else if(pid == 0)
 15     {//这段代码只有子进程能够运行到,因为在子进程中fork的返回值为0
 16         printf("this is child!---%d\n",getpid());
 17         sleep(5);
 18         exit(0);                                                                                                  
 19     }
 20     else
 21     {
 22        printf("this is parent!--%d\n",getpid()); //这段代码只有父进程可以行到 
 23     }//下面的代码父子进程都有可能运行到
 24     while(1)
 25     {
 26         printf("-----\n--%d",getpid());
 27         sleep(1);
 28     }
 29     return 0;
 30 }                        

输出结果为:
在这里插入图片描述

孤儿进程: 父进程先于子进程退出,子进程就成为了孤儿进程,运行在系统后台,并且被1号init进程收养。此时孤儿进程退出后不会称为僵尸进程,资源立即被回收。
孤儿进程的代码演示如下:

 1 #include <stdio.h>                                                                                                
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 
  5 int main()
  6 {
  7     printf("*******\n");
  8     pid_t pid = fork();
  9     if(pid<0)
 10     {
 11         printf("fork error!--%d\n",getpid());//getpid()是获取进程的pid,没有参数
 12         return -1;
 13     }
 14     else if(pid == 0)
 15     {//这段代码只有子进程能够运行到,因为在子进程中fork的返回值为0
 16         printf("this is child! the pid is %d\n",getpid());
 17     }
 18     else        
 19     {   
 20        printf("this is parent! the pid is %d\n",getpid()); //这段代码只有父进程可以行到 
 21			sleep(5);
 22         exit(0);  
 23     }//下面的代码父子进程都有可能运行到  
 24     while(1)
 25     {
 26         printf("-----\n--%d",getpid());
 27         sleep(1);
 28     }
 29     return 0;
 30 }              

五、 练习使用setenv, export等环境变量相关的函数和命令

  • env :查看所有环境变量
  • echo:打印指定环境变量的内容
  • set :查看shell中的所有变量信息(不只有环境变量)
  • export:将一个变量设置为一个环境变量
  • unset:删除一个变量(包含环境变量)

具体操作命令如下:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值