进程的管理、存储和运行


前言

该篇文章讲述进程的管理、存储和运行。


一、进程是什么?

进程,从概念的角度出发:是程序的一部分,一个程序可以有一个或多个进程;从内核的角度出发:是担当分配系统资源的实体。

1.描述进程

进程的信息(属性)放在进程控制块(PCB:process control block)的数据结构中,可以理解为进程属性的集合。
task_struct是Linux内核中描述进程的一种数据结构,其会被装载进RAM中。

task_struct内容分类:
标示符:描述本进程的唯一标示符,用来区别其他进程。(也可以理解为id码)
在Linux中可以使用geipid()函数获取进程的id。
状态:任务状态,退出代码,推出信号等。
优先级: 相对于其他进程的优先级。
程序计数器: 程序中即将被执行的下一条指令的地址。
内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
其他信息


二、进程管理

1.进程创建

在LInux中可以使用fork()函数通过系统调用创建进程。
图2.1 fork函数man手册
图2.2 fork函数描述与返回值
可以从图2.2中看出fork()返回值有两个,向父进程返回子进程的pid,向子进程返回0,可以用int类型或pid_t类型来接收返回的子进程pid。

int ret1 = fork();
pid_t ret2 = fork();
if(ret1 < 0){//可以用返回值判断进程创建是否成功。
	perror("fork");
	return 1;
}

2.进程状态

R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。

阻塞状态:

S睡眠状态(sleeping):意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠interruptible sleep))。
D磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
T停止状态(stopped): 可以通过发送 SIGSTOP信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
T跟踪停止状态(tracing stop):debug程序时,追踪程序遇到断电,进程暂停。

退出状态:
X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
Z僵尸状态(zombie):当进程退出并且父进程没有读取到子进程退出的返回代码(调用waitpid()读取)时子进程进入僵尸状态。

1.在系统中常见的状态是S(睡眠状态),因为进程运行的时间很短暂,在查看进程状态的时候很少出现R(运行状态)。
进程查看代码:

ps aux / ps axj 命令

2.D磁盘休眠状态专门针对磁盘设计,为了在后台下载或等待某个准备时间较长的资源,如果某个进程长时间没有得到回应且状态非D时,会被OS认为出现问题并杀死进程,D状态因此而生,该状态下的进程不可被杀掉,OS也不可以。但是该时间概念是针对计算机而言,并非人能感觉到的时间,因此也难被用户看到。

3.进入僵尸进程的子程序如果一直不被父进程读取,会持续处于Z状态,子进程的PCB信息需要一直被维护,因此会造成内存资源的浪费与内存泄漏。
如果父进程此时推出,子进程为孤儿进程,会被1号进程(init)领养且回收。


三、进程存储

1.内部存储

图3.1 程序地址空间

每个进程都会维护专属于自己的进程地址空间,这块空间为虚拟地址空间,通过页表完成物理空间的映射。

父进程使用fork()完成子进程的创建后,会与子进程共享一张虚拟地址空间(为了节约空间),但如果在某一处修改某一个变量,会发生写时拷贝,此时两个进程各自维护自己的地址空间,因此进程具有独立性。


四、进程运行

1.fork()函数特性

父进程调用fork()创建子进程后,会进入子进程执行程序,此时两个进程轮流调度,由调度器决定怎么执行,子进程退出后,父进程之后的代码继续向后执行。

2.进程退出

2.1.进程退出场景:
(1)运行完毕,正常退出(无论结果是否正确)
(2)进程异常终止

2.2.退出方法
(1)从main返回
(2)调用exit
(3)_exit
(4) return退出

exit()表示整个进程的推出,但是在推出之前会执行清理函数、冲刷缓冲和关闭流,如果调用_exit()则直接退出。
exit() = 用户定义的清理函数 + 冲刷缓冲、关闭流 + _exit()

3.进程等待

3.1.进程退出的必要性
2.2提到过的僵尸进程是因为父进程未等待回收导致的结果,因此为避免僵尸进程的出现以及得知子进程的执行结果,需要父进程等待回收子进程资源,获取子进程推出信息。
3.2.进程等待的方法
(1)wait()

pid_t wait(int* status)

返回值:成功则返回被等待进程的pid,失败返回-1。
参数:输出型参数,获取子进程退出状态,不关心可以设为NULL。

(2)waitpid

pid_t waitpid(pid_t pid, int* status, int options)

返回值:
被等待进程的pid,等待成功且等待进程退出;
0,等待成功但被等待进程未退出;
-1,等待失败。

参数:
pid:
-1,等待任意一个进程,与wait()相同;
>0,等待该pid对应的进程。
status:
WIFEXITED(status):若为正常终止子进程的状态,则为真;(查看子进程是否正常退出)
WEXITSTATUS(status):若WIFEXITED非零,提取子进程退出码。(查看进程退出码)
options:
WHOHANG:若pid指定的子进程没有结束,则waitpid()返回0,不等待,继续向后执行;若正常结束,则返回对应的pid。


五、 总结

本文简单介绍了进程的定义、创建、管理以及存储。
以上为全部内容。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值