Linux进程状态简述
在了解了进程的基本概念以及进程的创建等概念以后,接下来我们需要了解进程的状态。那么什么是进程状态呢?简单的说进程状态就是把一个进程在不同的时间划分为不同的状态。它描述了一个进程在什么时间做什么样的事情。
一般情况下进程有三种状态,就绪,运行,阻塞。
状态名称 | 描述 |
---|---|
就绪 | 进程已经具备运行条件,但是CPU还没有分配过来,拿到时间片就可以运行 |
执行 | 进程占用CPU,并在CPU上运行 |
阻塞 | 进程因等待某件事发生而暂时不能运行(如:I/O请求) |
三种状态的转换关系如下图:
Linux下的进程状态
状态名称 | 描述 |
---|---|
运行 | 正在运行或者拿到时间片就能运行,并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里 |
可中断休眠 | 意味着进程在等待事件完成 |
不可中断休眠 | 在这个状态的进程通常会等待I/O的结束 |
停止 | 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行 |
死亡状态 | 这个状态只是一个返回状态,你不会在任务列表里看到这个状态 |
通过系统调用fork()创建子进程
通过fork()创建子进程,以复制进程的方式创建一个子进程,代码共享,但数据独有。
代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int ret = fork();
printf("hello proc : %d!, ret: %d\n", getpid(), ret);
sleep(1);
return 0;
}
fork()函数,对于父进程返回的是子进程的pid是大于零的,对于子进程来说返回值是0;可以通过返回值对父子进程进行分辨;f返回值小于0表示创建失败,大于0为父进程,等于0为子进程。
代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int ret = fork();
if(ret < 0){
perror("fork");
return 1;
}
else if(ret == 0){ //child
printf("I am child : %d!, ret: %d\n", getpid(), ret);
}else{ //father
printf("I am father : %d!, ret: %d\n", getpid(), ret);
}
sleep(1);
return 0;
}
僵尸进程
僵尸状态:是一种特殊的状态,指一个进程退出了但是资源没有完全被释放的状态
僵尸进程:指使用fork创建子进程后,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。即处于僵尸状态的进程。
例子:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
if (pid < 0)
{
perror("fork");
return 1;
}
else if (pid == 0)
{
//创建子进程成功
printf ("我是子进程,我即将退出\n");
exit(0);
}
else
{
printf("我是父进程,我将睡眠30秒\n");
sleep(30);
}
printf(" 父进程退出\n");
return 0;
}
使用psps aux | grep testJiangshi 命令查看进程状态
僵尸进程的危害
因为子进程要告诉父进程,父进程交给子进程的任务完成得怎么样了,所以进程的退出状态必须被维持下去。可父进程一直不读取,那子进程就会一直处于僵尸状态。而维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,因为Z(僵尸)状态一直不退出,PCB就一直都需要维护,如果一个子进程创建了许多子进程,而不回收,就会造成内存资源的浪费。(就和电影中的僵尸一样,已经死亡,但是尸体仍然存在,如果“僵尸”越来越多,又无法销毁,就会把有限的空间完全占满)。
孤儿进程
孤儿进程:和僵尸进程产生的过程相反,孤儿进程是指父进程先于子进程退出,子进程成为孤儿进程运行在后台,父进程成为1号进程(孤儿进程退出不会成为僵尸进程,因为它会被1号进程直接处理)
代码:
#include <stdio.h>
#include <unistd.h>
#include <error.h>
#include <stdlib.h>
int main()
{
pid_t pid = fork();
if(pid < 0)
{
// 创建失败
perror("fork");
}
else if(0 == pid)
{
//子进程
printf("我是子进程!\n");
printf("pid: %d\tppid:%d\n",getpid(),getppid());
printf("我将睡眠10秒");//睡眠10秒,保证父进程先退出
sleep(10);
printf("pid: %d\tppid:%d\n",getpid(),getppid());
printf("子进程退出!\n");
}
else
{
printf("我是父进程!\n");
sleep(1);
printf("父进程退出");
}
return 0;
}
子进程成为孤儿进程,父进程成为1号进程