为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态,一个进程有如下几个状态
进程的状态
进程状态的意义:方便操作系统快速判断进程,完成特定的功能,比如调度,它的本质是将进程进行分类
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
- R运行状态(running):并不意味着进程一定在运行中,它表明进程要么是在运行中,要么是在运行队列中
- S睡眠状态(sleeping):意味着进程在等待事件完成(这里的睡眠有时也叫做可中断睡眠
- D磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态,在这个状态的进程通常会等待IO的结束
- T停止状态(stopped):可以通过发送
SIGSTOP
信号给进程来停止进程。这个被暂停的进程可以通过发送SIGCONT
信号让进程继续运行- X死亡状态(dead):这个状态只是一个返回状态,不会在任务列表里看到这个状态
R状态
前面我们讲到R状态的进程并不一定代表那个进程就在运行中,我们知道,CPU要管理进程是通过进程控制块PCB,而在任意时刻一定有许多的进程等待CPU的调用,就会有一个运行时队列(run_queue)来维护要调用的进程,这个运行时队列里面就是一个个的进程控制块,所以只要在运行时队列中 就是R状态。如下图
例子
1 #include<iostream>
2 #include<unistd.h>
3 using namespace std;
4 int main()
5 {
6 while(true)
7 {
11 cout << "hello ybb" << endl;
12 }
13 return 0;
14 }
~
S状态和D状态
当我们完成某种任务的时候,有可能当前的条件不具备,需要进程进行某种等待。比如我们在使用scanf
函数的时候,需要我们输入之后程序才会继续往下执行。这就是因为程序在等待我们从键盘上输入,此时程序就是S状态。我们知道运行时状态有一个运行时队列(run_queue)来维护进程,同样的等待状态也有一个等待队列(wait_queue)来维护我们在等待的进程,等到所有条件都具备时,就进入运行时状态。我们把,从运行状态的task_struct(run_queue),放到等待队列中,就叫做挂起等待(阻塞),从等待队列,放到运行时队列,被CPU调度就叫做唤醒进程。
1 #include<iostream>
2 #include<unistd.h>
3 using namespace std;
4 int main()
5 {
6 while(true)
7 {
8 // sleep(10);
9 int i = 0;
cout << "请输入一个数字:";
10 cin >> i;
11 cout << "hello ybb" << endl;
12 }
13 return 0;
14 }
- S状态:又称为可中断睡眠,或者浅度睡眠
- D状态:称为不可中断睡眠,或者深度睡眠,举个例子,假如我们在向磁盘中写数据,进程在等待磁盘写成功或写失败的返回值,此时进程就处于等待状态。而如果此时操作系统发现这个进程什么也没做就会过来杀进程,如果进程被杀磁盘写完后就找不到进程了,所以要把进程设置为D状态,进程就不会被操作系统杀
T状态
发送暂停信号将进程暂停,发送启动信号就将进程继续执行
测试
1 #include<iostream>
2 #include<unistd.h>
3 using namespace std;
4 int main()
5 {
6
7 while(true)
8 { }
9 return 0;
10 }
PS:带加号的
S+
叫前台进程,此时可以用ctrl + c
杀死进程,不带加号的叫后台进程,./myproc &
运行就是后台进程
X状态
释放进程资源 = 进程相关内核数据结构 + 代码和数据
Z状态–僵尸进程
- 僵尸进程(Zombies)是一个比较特殊的状态。当子进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵尸进程。也就是说,子进程被杀死了,但是父进程没有回收子进程的资源,就产生了僵尸进程
- 僵尸进程会以终止状态保持再进程表中,并且会一直等待父进程读取退出状态代码
- 总结:只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
举个例子:
1 #include<iostream>
2 #include<unistd.h>
3 using namespace std;
4 int main()
5 {
6 pid_t pid = fork(); // 创建子进程
7 if(pid == 0)
8 {
9 while(true)
10 {
11 cout << "hello ybb" << endl;
12 sleep(2);
13
14 }
15 }
16 else{
17 sleep(50);
18 }
19
20 // while(true)
21 // { }
22 return 0;
23 }
孤儿进程
- 父进程如果提前退出,那么子进程退出后,进入Z状态之后,该如何处理?
- 父进程先退出,子进程就称之为“孤儿进程”
- 孤儿进程要被1号进程领养,所以孤儿进程由1号进程回收
举个例子
2 #include<unistd.h>
3 using namespace std;
4 int main()
5 {
6 pid_t pid = fork();
7 if(pid == 0)
8 {
9 cout << "我是子进程" << endl;
10 sleep(50);
11 }else{
12 cout<< "我是父进程" <<endl;
13 sleep(3);
14 exit(0);
15 }
16 return 0;
}