赞
踩
进程 = task_struct + 可执行程序
进程不是一 直在运行的,可能在等待软硬件资源,比如scanf后,程序停止运行了,在等待用户输入。进程放在CPU上,也不是一直在运行的。时间片:进程在CPU上的时间,过了就会被拿下。
先简单看看进程排队:
所谓的进程排队,一定是在等待某种资源,排队是进程的PCB(task_struct)在排队,而不是进程的可执行程序在排队。
一个task_struct(进程的PCB)可以被连入多种数据结构中, 在Linux内核中,每一个进程的PCB不是连入到单链表中的,而是连入到双链表的(队列可以用链表实现),这个结构和书本上学习的双链表结构一样的但用法不同而已,请看图解:
图一:
注释:如果像下图这样管理PCB的话(也就是每一个进程PCB中包含两个指针,但是这样只能连入一到一个数据结构中,如果想要连入到多种数据结构中,必须加指针,浪费空间,并且难维护),所以这种结构是不合适的。
图二:
注解:每一个进程的PCB中,包含特殊的结构体,然后将这个结构体指针放入双链表中进行管理,这样,就可以通过这个结构体指针找到进程的PCB,这个结构体指针也可以连入多种数据结构中。(利用struct listnode在对应进程的PCB中偏移量计算PCB的地址:(task_struct*)(&n-&((task_struct)0-> n)。如果PCB中存在很多个特殊的结构体,就可以将PCB连入到很多不用的数据结构中进行管理。
所谓的状态,其实就是一个整型变量,在task_struct里面的一个整型变量:
状态决定了什么?
状态决定了下一步的后续动作。
一个CPU一个运行队列。
如简图:
运行状态:一个进程的PCB在CPU的运行队列上,不一定正在运行,把该进程的状态成为运行状态;
阻塞状态 :
每一个设备为了操作系统能够管理。都会被先描述,后组织。将设备用一个结构体描述,结构体里面可能会包含设备类型,状态,以及当前设备的等待队列等。
当一个进程在等待软硬件资源的时候,如果资源没有就绪,例如scanf时,操作系统会将该进程PCB从与逆行队列拿下来,状态由运行改为阻塞,连入到等待的资源提供的的等待队列中,等待资源;
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 */
};
Linux进程状态转换图:
测试:使用指令
# ps ajx | head -1 && ps ajx | grep myprocess
测试代码1:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4
5 int main()
6 {
7 while(1)
8 {
9 printf("i am a proces id:%d\n",getpid());
10 sleep(1);
11 }
12 return 0;
13 }
运行结果:
测试代码2:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4
5 int main()
6 {
7 while(1)
8 {
9 printf("i am a proces id:%d\n",getpid());
10 //sleep(1);
11 }
12 return 0;
13 }
运行结果:
测试代码3:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4
5 int main()
6 {
7 while(1)
8 {
9 //printf("i am a proces id:%d\n",getpid());
10 //sleep(1);
11 }
12 return 0;
13 }
运行结果:
指令(前台进程变为后台进程)
# ./myprocess &
可以将前台进程变为后台进程,后台进程使用键盘ctrl+c不能杀掉,只能用命令kill -9 杀掉;
例如:
测试代码:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4
5 int main()
6 {
7 while(1)
8 {
9 printf("i am a proces id:%d\n",getpid());
10 sleep(1);
11 }
12 return 0;
13 }
T状态的测试:
测试代码:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4
5 int main()
6 {
7 while(1)
8 {
9 printf("i am a proces id:%d\n",getpid());
10 sleep(1);
11 }
12 return 0;
13 }
运行结果:
T状态:让进程处于暂停状态。
t状态的测试:
当我们调试代码的时候,在每次单步执行的时候,程序会处于t状态(停止状态);
示例:
Z状态,僵尸状态:当一个进程退出后,但是该进程的状态需要自己维持住,供上层读取。也就是进程从退出到资源被清理的这个时间段,进程所处于的状态。
测试代码:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 5 int main() 6 { 7 pid_t id = fork(); 8 if(id==0) 9 { 10 int cnt = 5; 11 while(cnt) 12 { 13 printf("i is child id:%d pid:%d\n",getpid(),getppid()); 14 sleep(1); 15 cnt--; 16 } 17 exit(0); //让子进程直接退出 18 } 19 //father 20 while(1) 21 { 22 printf("i is father id:%d pid:%d\n",getpid(),getppid()); 23 sleep(1); 24 } 25 return 0; 26 }
结果:5秒过后子进程状态变为Z(僵尸状态):因为进程退出后,退出信息你没有被读取;怎么读取后续文章再给出。
如果一个进程的父进程已经退出,但是子进程还没有退出,这个子进程就被叫做孤儿进程。
这是孤儿进程会变为后台进程,只有不能ctrl+c杀掉,可以通过kill命令。
这个进程会被1号进程(操作系统)所领养;如果不被领养,就变成没有主的进程,当程序退出时,就会一直为僵尸进程,就会一直暂用资源(空间),所以孤儿进程会被1号进程领养,这样该进程的资源还可以被操作系统所回收。
测试代码:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 5 int main() 6 { 7 pid_t id = fork(); 8 if(id==0) 9 { 10 int cnt = 50; 11 while(cnt) 12 { 13 printf("i is child id:%d pid:%d\n",getpid(),getppi d()); 14 sleep(1); 15 cnt--; 16 } 17 exit(0); //让子进程直接退出 18 } 19 //father 20 int cnt = 5; 21 while(cnt) 22 { 23 printf("i is father id:%d pid:%d\n",getpid(),getppid ()); 24 sleep(1); 25 cnt--; 26 } 27 printf("父进程退出\n"); 28 return 0; 29 }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。