进程
- 进程
- PCB
- 进程的定义
- 进程的组成
- 进程模式
- 进程的状态
- 进程的运行
- 进程的创建
- 进程的结束
- 孤儿进程
- 僵尸进程
- 僵尸进程的危害
- 进程的创建
- pid
- fork
- wait
- 案例
进程
PCB
从操作系统理解进程概念-------先描述,后组织
为了使参与并发执行的程序能独立的运行,必须为之配置一个专门的数据结构-----task_struct,称为进程控制块(PCB)。进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
系统利用PCB来描述进程的基本情况和运行状态,进而控制和管理进程(也就是组织)进程。
相应地,由程序段、相关数据段和PCB三部分构成了进程映像(进程实体)。所谓创建进程,实质上是创建进程映像中的PCB;而撤销进程,实质上是撤销进程的PCB。值得注意的是,进程映像是静态的,进程则是动态的。
进程的定义
进程的定义:一个运行中的程序
例如:
源程序文件 ----> 可执行文件
狭义定义:进程就是一段程序的执行过程。
广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元内存最小的单位:bit(位)
内存最小的管理单位:字节
进程的组成
进程由三部分组成,代码段,数据段,堆栈段
也就是程序,数据,进程控制块
数据:全局变量,静态变量(已初始化,未初始化),只读变量,局部变量
代码:进程的源代码
堆栈:变量,手动内存分配(malloc new)
进程模式
程序在运行的时候,一般为2种模式
1.内核模式:内核上的程序
2.用户模式:用户自己写的程序,应用程序正常运行
进程的状态
用来显示进程信息可以用
top命令,或者 ps -aut
pstree 进程数命令
进程的状态:
1.R(running) : 运行态
2.S(sleep):睡眠态
3.
4.
5.
6.
7.
进程的运行
1.手动运行,命令以及执行可执行程序
2. 调读
nice , renice: 控制进程是否让步
kill
crontab
bg
进程的创建
- system:在程序中执行命令
- fork, vfork : 创建子进程
- exe
进程的结束
1.自然结束
2.被动结束:
os 结束 被内核进程结束
被本进程或者其他进程干掉
孤儿进程
父进程结束,子进程还在运行的子进程被称为孤儿进程。
一个父进程退出,而它的一个或多个子进程还在运行,那么这些子进程将成为孤儿进程。孤儿进程将被 init 进程(进程号为1)所收养,并由
init 进程对它们完成状态收集工作
僵尸进程
一个进程使用 fork 创建子进程,如果子进程退出,而父进程并没有调用 wait 或 waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这种进程称之为僵死进程。
3.提防僵尸进程产生(占用的资源不会被释放掉)
首先你要理解,进程本身占用的资源以及进程运行时占用的资源进程运行时占用的资源:会释放
进程本身占用的资源:不会被释放僵尸进程产生的原因:
子进程结束了,父进程没有回收它的资源
(也就是父进程先于子进程结束,没有回收子进程的资源)
怎么防止僵尸进程
1.父进程结束前,子进程结束,父进程回收子进程的资源
2.父进程结束后,子进程被父进程的父进程收养,爷爷进程回收子进程的资源。
僵尸进程的危害
僵尸进程虽然不占有任何内存空间,但如果父进程不调用 wait() / waitpid() 的话,那么保留的信息就不会释放,其进程号就会一直被占用,而系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程,此即为僵尸进程的危害
进程的创建
在Linux中,所有的进程都可以看做是init()进程的子进程,孙子进程,重孙进程等。
pid
,每个进程在系统中都有一个唯一·的非负整数表示的进程ID,用getpid() 获取进程pid, getppid(), 获取当前进程的父进程的pid
每一个进程都有对应的目录在/proc目录下
用kill()函数
注意:
kill函数的第一个参数是pid_t的数据类型
pid_t 实际上是一个int类型
fork
没有参数,有一个返回值
fork: 用克隆的方式,创建一个进程,创建成功,返回这个进程的id
克隆:全盘复制,包括这个进程的上下全文
子进程拷贝了父进程的上下文
进程的上下文:进程运行这个位置的地方(数据,时间,状态)
fork实际上,创建的是子进程调用fork的进程, 是父进程
fork创建的进程, 是子进程
wait
wait()函数,是用来防止僵尸进程,
作用:让父进程结束的在子进程之后,如果父进程结束的早,用了wait(),可以起到延迟效果,等子进程结束,父进程才结束
注意:这里有个waitpid()函数,
可以指定进程
案例
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
if(fork())
{
printf("father = %d\n ", getpid());
}
else
{
for(int i = 0; i < 3; i++)
{
printf("son = %d\n ", getpid());
}
}
printf("end = %d\n", getpid());
return 0;
}
由运行结果可知,
father 为父进程
son为子进程
end 都被执行了2次
因为用了fork函数之后,
子进程被创建,子进程拷贝的父进程的上下文(fork函数的原理)
注意:这里是父进程先结束,子进程的资源没有被回收,造成的僵尸进程
用wait()函数,避免僵尸进程
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
int main()
{
if(fork())
{
printf("father = %d\n ", getpid());
wait(0); //避免僵尸进程的出现
}
else
{
for(int i = 0; i < 3; i++)
{
printf("son = %d\n ", getpid());
}
}
printf("end = %d\n", getpid());
return 0;
}
这里就是子进程比父进程先结束