进程概念
运行中的程序。
对于操作系统来说就是PCB进程控制块,在Linux中就是一个task_struct结构体。
是操作系统对程序运行的动态描述,系统通过这个描述实现程序运行的管理和调度。
程序运行示例
要运行main这个程序,操作系统找到对应main的PCB,在PCB上读取main运行所需要的的信息,加载到cpu上,cpu就开始运行这个程序了。
PCB描述的信息
(task_struct内容)
- 内存指针:包括程序代码和进程相关数据的指针。
- 上下文数据:进程执行时处理器的寄存器中的数据。
- 程序计数器:程序中即将被执行的下一条指令的地址。
- 进程ID:用于标识进程的唯一数值。
- I/O信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 进程优先级:相对于其他进程的优先级。
- 进程状态:运行态,可中断休眠态,不可中断休眠态,死亡态,僵尸态……
查看进程
可以通过/proc、top 、ps等指令查看进程状态。
/proc:
top:
ps :
通过系统调用获取进程标示符
进程id:PID
父进程ID:PPID
printf("pid = %d\n",getpid());
printf("ppid = %d\n",getppid());
通过系统调用创建进程
fork()
:
当程序调用fork函数时,系统会创建新的进程并为其分配资源;然后,会将原来进程的相关内容全部复制到新的进程中。
通过返回值来区分父子进程:
返回值为0时,表示子进程。
返回值大于0时,表示父进程,且返回值为新创建的子进程的PID。
返回值小于0时,表示fork出现错误。
示例
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t fpid;
fpid=fork();
if(fpid<0)
printf("error");
else if(fpid==0)
{
printf("我是子进程,我的进程id是%d\n",getpid());
}
else
{
printf("我是父进程,我的进程id是%d\n",getpid());
}
return 0;
}
进程状态
- 运行态R:不一定表示进程正在运行中,表明进程在运行中或者在运行队列里。
- 可中断休眠态S: 可以被中断的休眠状态,满足唤醒条件或者休眠被中断进入运行态。
- 不可中断休眠态D:不能被中断的休眠态,满足唤醒条件进入运行态。
- 停止态T:程序停止运行(会被调度)
- 僵尸态Z:进程已经退出不再调度了,但是进程的资源还没被释放等待处理的状态
僵尸进程
是处于僵尸态的进程,是一种退出了,资源还没完全释放的进程。
产生过程:
子进程先于父进程退出,父进程没有关注到子进程的退出,系统不会完全释放子进程的资源,子进程进入僵尸态。
子进程退出后,在PCB中保存了自己的退出返回值,在父进程没有关注处理的情况下,PCB资源不会被释放。
模拟僵尸进程
让父进程休息30s后退出,在另一个终端查看进程状态。
子进程退出,父进程休眠没有关注到子进程退出,子进程进入僵尸态
父进程休眠30s后退出。
危害
资源泄露:
- pcb的资源没法被释放
- 用户能创建的进程数有限
孤儿进程
父进程先于子进程退出,子进程会成为孤儿进程,运行在后台,父进程成为一号进程。
模拟孤儿进程
发现pid为6080的子进程还在后台运行,S态。
子进程pid为6080的进程父进程变成了1号进程。