目录
前言:
正文:
1.R运行状态(running)
2.睡眠状态(sleeping)
3.D磁盘休眠状态(Disk sleep)
4停止状态(stop)
5僵尸状态(Z)
6 孤儿进程
补充知识:前后台进程
为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在linux内核里,进程有时候也叫任务)
下面的状态在kernel源码中的定义:
/** 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 */};
运行态具体是指:当操作系统把CPU资源分配给进程时(cup对进程进行调度),进程会在运行队列里面排队(运行状态)在一个时间段内,所有的进程都会被执行,并发执行。在运行状态下,进程会执行它所分配的任务。当进程的时间片用完后,进程就会被挂起(带走自己的上下文),等待下一次CPU调度。
我们可以看一下在Linux下的R状态【查看进程状态的命令:ps ajx/aux 】。如下:
process.c
1 #include
2 #include
3 #include
4 int main()
5 {
6 pid_t id = fork();
7 if(id < 0){ perror("fork");
8 return 1;
9 }
10 else if(id == 0){
11 // child
12 printf("I am child, pid :[%d] ppid:[%d]\n", getpid(),getppid());
13 sleep(20);
14
15 }else{
16 //parent
17 printf("I am parent, pid: [%d] ppid:[%d]\n", getpid(),getppid());
18 sleep(10);
19 exit(0);
20
21 }
22 return 0;
23 }
Makefile
myprocess:process.c
2 gcc -o myprocess process.c
3
4 .PHONY:clean
5 clean:
6 rm -r myprocess
7
8 .PHONY:catP
9 catP:
10 ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep
11
通过指令对进程状态进行查看
我们会发现不管是父进程还是子进程,我们看到的状态都是S+,这是因为对于cpu来说,将数据回显到显示器的任务在电光火石之间就完成了,我们很难捕捉到,所以我们大部分捕捉的动作他都是在等待队列中进行排队。
(R+是在运行队列中被操作系统管理这,也是在排队,他不一定被cpu调度)排队类似下图
为了捕捉,我们可以将打印语句屏蔽,让其一直死循环,这样我们就可以在调度的时间片内捕捉到其运行状态。
睡眠状态是指:当进程被调用而等待某个事件的发生时,该进程就会进入睡眠状态。通俗来讲,当我们要完成某种任务的时候,任务条件不具备,需要进程进行某种等待。(也叫进程阻塞)
进程等待时,都是在等待CPU资源吗?答案是:并不是!
睡眠状态被认为是一种阻塞状态,因为该进程在等待发生的事件情况下不能真正地执行,所以CPU的资源也就会被阻塞。只有当该事件发生,进程才能被唤醒并继续执行。
补充:s+是一种前台进程,我们可以通过输入信号将其关闭,也就是键盘上的ctrl+c将进程杀死,(会在信号章节进行详细介绍)。
D磁盘休眠状态(Disk sleep)表示进程因等待磁盘I/O操作时而被阻塞,并且进程等待的操作可能会很慢,也可能永远不会完成。当出现大量相同操作的时候,就会出现休眠状态。
例如有一个进程需要把数据写入磁盘,且数据量很大。而写入磁盘的过程相对来说并不是很快,进程需要等待一段时间。等待的过程中,同时也占用了CPU的资源, 我们都知道操作系统是不会浪费任何内存,所以他有杀死进程的功能。如果该进程写入的数据很重要,需要磁盘读取数据完成后的返回信息。但也可能会被误操作给删除。所以给他一个免死金牌D状态,该进程不可被操作系统终止。
在Linux系统中,有些进程可能预期会处于D状态,例如,磁盘I/O操作比较耗时的进程。而对于其他类型的进程,处于D状态通常是不正常的,需要进行诊断和解决。常用的解决方法包括重启系统、更换设备等。
T停止状态(stopped)表示进程已经被挂起,不再运行,但是它尚未完成或终止。进程可以进入停止状态是由于收到一个SIGSTOP、SIGTSTP、SIGTTIN或者SIGTTOU信号,以及调试器进程发送的SIGHUP、SIGINT、SIGQUIT、SIGILL、SIGTRAP、SIGABRT、SIGBUS、SIGFPE、SIGSEGV、SIGPIPE、SIGALRM、SIGTERM、SIGURG、SIGXCPU、SIGXFSZ和SIGSTOP信号。
我们可以利用kill - 18 kill-19让进程 恢复或者暂停。
与死亡状态相对应的还有一个 僵尸 T 状态
通俗来说,僵尸状态 是给 父进程 准备的
当 子进程 被终止后,会先维持一个 僵尸 状态,方便 父进程 来读取到 子进程 的退出结果,然后再将 子进程 回收。
单纯的在 bash 环境下终止 子进程,是观察不到 僵尸状态 的,因为 bash 会执行回收机制,将 僵尸 回收。
fork()
函数自己创建 父子进程
关系,观察到这一现象
1 #include
2 #include
3 #include
4 int main()
5 {
6 pid_t id = fork();
7 if(id < 0){ perror("fork");
8 return 1;
9 }
10 else if(id == 0){
11
12 // child
13 printf("I am child, pid :[%d] ppid:[%d]\n", getpid(),getppid());
14 sleep(5);
15
16 }else{
17 //parent
18 printf("I am parent, pid: [%d] ppid:[%d]\n", getpid(),getppid());
19 sleep(20);
20 exit(0);
21
22 }
23 return 0;
24 }
~
~
~
父子进程
父进程
,此时 子进程
会被OS领养子进程
的 父进程
变为 1号进程
子进程
就变成了一个 孤儿进程
我们可以通过以下代码验证当父进程先退出的时候,子进程是不是被1号进程接管。
1 #include
2 #include
3 #include
4 int main()
5 {
6 pid_t id = fork();
7 if(id < 0){ perror("fork");
8 return 1;
9 }
10 else if(id == 0){
11
12 // child
13 printf("I am child, pid :[%d] ppid:[%d]\n", getpid(),getppid());
14 sleep(35);
15
16 }else{
17 //parent
18 printf("I am parent, pid: [%d] ppid:[%d]\n", getpid(),getppid());
19 sleep(5);
20 exit(0);
21
22 }
23 return 0;
24 }
~
Linux中运行的程序可以在前台(foreground)或者后台(background)运行。前台程序是在当前终端会话中运行的程序,而后台程序则是在系统内部运行的,没有与用户终端会话相关联。上述带 ‘+’ 号的就是在前台运行的程序,不带 ‘+’ 号的就是在后台运行的程序。
当用户在终端中输入运行一个程序的命令时,该程序默认以前台方式运行,它会在终端上打印输出并且用户必须等待程序执行完成。
如果在命令末尾加上 & 符号,就可以让程序在后台运行。具体如下图:
如果需要与后台程序交互,可以使用一些特殊的命令,如:jobs, fg等,来查看和控制程序的状态。 fg 指令就可吧后台进程转换到前台运行。例如:
$ jobs #查看后台运行的程序
$ fg %1 #将后台中的程序1转为前台运行