Linux 进程状态

Linux的进程在不同的周期内可以拥有不同的状态,各个状态之间也可以进行切换,下面就来简单介绍一下Linux操作系统下的各个进程状态。

  • 运行态(TASK_RUNNING):这种状态下进程已经获得CPU使用权,或者已经准备就绪,随时都可以运行。在一些实时操作系统(比如ucos)中,把处于准备就绪的进程称为就绪态,但是Linux把就绪态和运行态都统称为运行态。
  • 可中断睡眠态(TASK_INTERRUPTIBLE):当进程等待的资源没有被满足时,进程就会进入睡眠状态,进入中断的睡眠态的进程有两种唤醒方法,一种是等待的资源被满足,另一种是被信号唤醒,被唤醒后的进程就进入了运行态(在ucos等实时操作系统中会进入就绪态)。
  • 不可中断睡眠态(TASK_UNINTERRUPTIBLE):不可中断睡眠态和可中断睡眠态一样,都是进程的资源没有被满足而进入睡眠,但是进入不可中断睡眠态的进程不能被信号唤醒,只有当进程资源满足时才会唤醒。被唤醒后的进程就进入了运行态(在ucos等实时操作系统中会进入就绪态)。
  • 停止态(TASK_STOPPED):当进程收到SIGSTOP、SIGTSTP、SIGTTIN、SIGTTOU时,进程会进入停止态,向进程发送SIGCONT可让进入进入运行态。进入停止态的进程不会被调度器调度。
  • 僵尸态:(TASK_ZOMBIE):当子进程退出时,父进程没有回收子进程的资源,这是子进程就会进入僵尸态。

Linux 进程状态_第1张图片

下面通过几个的程序简单来说明一些进程的一些状态

  • 运行态
#include 
#include 
#include 
int main(void)
{
	printf("hello getpid = %d getppid = %d\r\n",getpid(),getppid());
	while(1);
	
	return 0;

}

我们让上述程序在打印出自己的pid和父进程的pid后就一直进入死循环,让他一直运行,观察其状态。
在这里插入图片描述
利用ps -aux命令查看进程号为4727的进程状态
在这里插入图片描述
可以看到图中用红笔圈出来的进程号为4727的进程状态为R+,表示该进程正在处于运行状态。

  • 睡眠态
#include 
#include 
#include 

int main(void)
{
	printf("hello getpid = %d getppid = %d\r\n",getpid(),getppid());
	sleep(10);
	return 0;

}

在程序中加入sleep函数,让其睡眠10,运行程序观察其状态。
在这里插入图片描述

在这里插入图片描述
可以看到进程号为4751的进程状态为S+,表示该进程进入睡眠态。

  • 僵尸态
    僵尸态进程是当子进程退出时,父进程没有回收子进程的资源导致子进程进入僵尸态。下面来看一段代码,模拟子进程进入僵尸态。
#include 
#include 
#include 
#include 
#include 
int main(void)
{
	pid_t pid = -1;
	int status;
	pid = fork();
	
	if(pid == 0)  // 子进程
	{
		printf("I am child getpid = %d getppid = %d\r\n",getpid(),getppid());
		exit(1);
	}
	else if(pid > 0)  // 父进程
	{
		printf("I am father getpid = %d getppid = %d\r\n",getpid(),getppid());
		sleep(20);
		waitpid(pid,&status,0);
	
	}
	else   // fork失败
	{
		printf("fork error\r\n");
	}
	
	return 0;

}

代码开始首先会调用fork函数生产子进程,在子进程中会打印出自己的pid和父进程pid,然后调用exit函数退出。而父进程会睡眠20秒,最后才回收子进程资源。
在这里插入图片描述
在这里插入图片描述
可以看到当程序运行时,父进程就立刻进入睡眠,此时状态为S+,进入睡眠态。而子进程则立刻退出,此时父进程并没有及时回收子进程资源,导致子进程进入了僵尸态,进程状态此时为Z+。

  • 孤儿进程
    操作系统还有一个叫孤儿进程的概念,孤儿进程是当父进程比子进程早退出时,导致子进程没有父进程,这时的子进程就被称为孤儿进程。所有孤儿进程的父进程此时变为进程1,也就是init进程成为孤儿进程的父进程。下面来看一段程序。
#include 
#include 
#include 
#include 
#include 
int main(void)
{
	pid_t pid = -1;
	int status;
	pid = fork();
	
	if(pid == 0)  // 子进程
	{
		while(1)
		{
			printf("I am child getpid = %d getppid = %d\r\n",getpid(),getppid());
			sleep(1);
		}
		
	}
	else if(pid > 0)  // 父进程
	{
		printf("I am father getpid = %d getppid = %d\r\n",getpid(),getppid());
		sleep(5);
		exit(1);
	
	}
	else   // fork失败
	{
		printf("fork error\r\n");
	}
	return 0;

}

首先程序会调用fork函数创建子进程,然后子进程会每隔1秒循环打印出自己的pid和父进程pid。父进程在打印出自己的pid后,睡眠3秒退出。此时观察子进程打印出的pid值。
Linux 进程状态_第2张图片
Linux 进程状态_第3张图片
可以看到刚开始运行时子进程的pid为72,72是创建子进程的父进程的进程号,3秒后父进程退出,父进程退出前并没有回收子进程的资源,这时的子进程变成了孤儿进程。此时子进程的父进程进程号变成了进程1,也就是init进程成为了孤儿进程的父进程。

你可能感兴趣的:(linux)