/ 程序:硬盘上的一个普通文件,里边包含着代码和数据。
进程:把程序运行起来,加载到内存中,操作系统为了管理进程,会创建一个PCB将进程描述起来,再通过一个链表将多个进程组织起来。
1.进程基本概念:
课本概念:程序的一个执行实例,正在执行的程序。
内核观点:担当分配系统资源(CPU时间,内存)的实体
如何管理进程呢:
先将进程描述起来,再将进程组织起来。
#0# 描述进程:
- 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合
- 一般被称为PCB,Linux操作系统下的PCB是:task_struct
- task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。
PCB中中的信息:
- 1.标识符:描述本进程的唯一标识符
- 2.状态:任务状态
- 3.优先级:相对于其他进程的优先级
- 4.程序计数器:程序中即将被执行的下一条指令的地址
- 5.内存指针:包括程序代码和进程相关数据的指针
- 6.I/0状态信息:
- 7.上下文数据:进程执行时处理器的寄存器中的数据。(进程间切换,体现了进程的动态特性)
- 8.记账信:处理器时间总和等。
- 9.其他
1.1组织结构
所有运行在系统里的进程都以task_struct链表的形式存在内核里
1.2查看进程
- 1.通过/proc系统文件查看
- 2.通过top和ps这些用户级工具
1.3通过系统调用获取进程标示符
- 进程id(PID)
- 父进程id(PID)
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
printf("pid : %d\n", getpid());//打印子进程ID
printf("ppid : %d\n", getppid());//打印父进程ID
return 0;
}
1.4通过系统调用创建进程-fork函数
- fork由两个返回值
- 父子进程代码共享,数据各自开辟空间,私有一份(写实拷贝)
- fork之后要用if分流(子进程返回0,父进程返回子进程的PID)
- 父子进程先后顺序不确定
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
int ret = fork();
if (ret == 0)
printf("I am child : %d, ret : %d\n", getpid(), ret);
else
printf("I am father: %d, ret : %d\n", getpid(), ret);
sleep(1);
return 0;
}
2.进程状态
- 1.R运行状态:并不意味着进程一定在运行中。它表明进程在运行中或运行队列里。
- 2.S睡眠状态(可中断睡眠):意味着进程在等待事件完成。
- 3.D磁盘休眠状态(不可中断睡眠):进程通常等待IO结束
- 4.X死亡状态:释放进程间资源,这个状态是一个返回状态,不会再任务列表中看到这个状态。
S(睡眠)和D(磁盘休眠)状态的区别:
S状态在休眠期间可以被操作系统操作,D状态不能被操作系统杀死,D状态一般在我们进行IO的时候出现
ps:可以用 kill -19, kill -18 等信号来改变进程状态
2.1僵尸状态
- 一个特殊的状态。当进程退出并且父进程没有读取到紫禁城推出的返回代码就会产生僵尸进程
- 僵尸进程会以终止状态保持在进程表中,一直等待父进程读取退出状态代码
- 只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
- 总而言之,僵尸状态是为了让父进程有机会读取子进程的状态
让我们看看僵尸状态的代码:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t id = fork();
if(id > 0)
{
printf("parent[%d] is sleeping", getpid());
sleep(30);
}
else
{
printf("child[%d] is begin", getpid());
sleep(5);
exit(EXIT_SUCCESS);
}
return 0;
}
左边为运行窗口,右边为监视窗口
有此可见,从第5秒开始,由于子进程退出但父进程没有收到子进程退出的返回代码,导致子进程进入僵尸状态
僵尸进程的危害:
- 如果子进程一直不读取,子进程会一直处于Z状态
- 由于维护僵尸状态必须要用到PCB来维护,如果Z状态一直不退出PCB要一直维护
- 如果出现大量僵尸进程,而且父进程就是不回收,那么就会造成内存泄漏。
2.2孤儿进程
- 父进程如果提前退出,子进程就被称为孤儿进程
- 孤儿进程被1号init进程领养,并由其回收
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t ret = fork();
if(ret == 0)
{
printf("I am child : %d\n", getpid());
sleep(10);
}
else
{
printf("I am father: %d\n", getpid());
sleep(3);
exit(0);
}
return 0;
}
由于父进程先退出了,子进程就成了孤儿进程
2.3进程优先级:
- 基本概念:cpu资源分配的先后顺序,就是进程的优先权
- 优先权高的进程有优先执行的权力。
- 还可以把进程运行到指定CPU上,这样一来,可以优先做重要的事。
查看系统进程
在linux和unix系统中,用 ps -l会输出进程的相关属性:
我们需要注意几个重要信息:
- UID:代表执行者的身份
- PID:代表进程的代号
- PPID:代表该进程父进程的代号
- PRI:代表这个进程可被执行的优先级,值越小越早被执行
- NI:代表这个进程的nice值
关于优先级的概念:
- 1.PRI越小,进程优先级越高
- 2.NI(nice值)表示进程优先级的修正值
- 3.PRI值越小越先被执行,如果存在NI值,PRI实际值 = PRI显示值 + NI
- 4.nice其取值范围共有40各级别,-19 ~ 20.
需要注意:NI值不是优先级,nice值是进程优先级的修正数据。
查看进程优先级的命令:
- top
- 进入后按“r”->输入进程pid->输入Nice值
进入top后修改otto的NICE值
结果:
3.一些其他概念:
- 竞争性:CPU的数量比系统进程的数目多很多,所以进程间具有竞争属性。为了更合理的竞争,有了优先级的概念
- 独立性 :多进程运行,需要独享各自的资源,他们互不干扰
- 并行:多个进程在多个CPU下分别同时进行。
- 并发:多个进程在一个CPU下采用进程切换的方式,在一段时间内使得多个进程得以推进。