- 程序地址空间
- 进程地址空间
- 分页&虚拟地址空间
- 进程调度队列
- 优先级
- 活动队列
- 过期队列
- active指针和expried指针
- 总结
#include2 #include 3 #include 4 #include 5 int g_val = 100; 6 int g_unval; 7 int main(int argc,char *argv[],char *envp[]) 8 { 9 printf("code addr:%pn",main); W> 10 char* str = "hello world"; 11 printf("read only addr:%pn",str); 12 printf("init addr:%pn",&g_val); 13 printf("unint addr:%pn",&g_unval); E> 14 int *p = malloc(10); 15 printf("heap addr:%pn",p); 16 17 printf("stack addr:%pn",&str); 18 printf("stack addr:%pn",&p); 19 int i; 20 for( i = 0;i < argc;i++) 21 { 22 printf("argc addr:%pn",argv[i]);//ls -a -l 23 } 24 while(envp[i]) 25 { 26 printf("envp addr:%pn",envp[i++]); 27 } 28 }
#include2 #include 3 #include 4 #include 5 int g_val = 100; 6 int g_unval; W> 7 int main(int argc,char *argv[],char *envp[]) 8 { 9 pid_t id = fork(); 10 if(id == 0) 11 { 12 //child 13 printf("child:pid :%d,ppid :%d,g_val :%d,&g_val :%pn",getpid(),getppid(),g_val,&g_val); 14 } 15 else{ 16 //father 17 printf("father:pid :%d,ppid :%d,g_val :%d,&g_val :%pn",getpid(),getppid(),g_val,&g_val); 18 } 19 sleep(1); }
把g_val 改为200
#include2 #include 3 #include 4 #include 5 int g_val = 100; 6 int g_unval; W> 7 int main(int argc,char *argv[],char *envp[]) 8 { 9 pid_t id = fork(); 10 if(id == 0) 11 { 12 //child 13 g_val = 200; 14 printf("child:pid :%d,ppid :%d,g_val :%d,&g_val :%pn",getpid(),getppid(),g_val,&g_val); 15 } 16 else{ 17 //father 18 printf("father:pid :%d,ppid :%d,g_val :%d,&g_val :%pn",getpid(),getppid(),g_val,&g_val); 19 } 20 sleep(1); 21 }
父子进程,输出地址是一致的,但是内容不一样
结论
- 变量内容不一样,所以父子进程输出的变量绝对不是一个变量
- 地址值是一样的,说明该地址不是物理地址
- LINUX下,这种地址叫做虚拟地址
- C/C++语言所看到的地址,全都是虚拟地址。物理地址用户一概看不到,由OS统一管理
OS负责将虚拟地址转化为物理地址
所以说程序地址空间是不标准的,准确应该是进程地址空间
写入(改变)时父子进程在数据层面发生了分离
子进程写入,不影响父进程,因为进程独立性
同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址
一个CPU具有一个runqueue
- 如果有多个CPU就要考虑进程个数的负载均衡问题
- 普通优先级100~139(与nice取值相对应)
- 实时优先级0~99
- 时间片还没有结束的所有进程都按照优先级放在该队列
- nr_active:总共有多少个运行状态的进程
- queue[140]:一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以数组的下标就是优先级
- 从该结构中,选出一个最适合的进程
1、从0下标开始遍历queue[140]
2、找到第一个非空队列,该队列必定为优先级最高的对列
3、拿到选中队列的第一个进程,开始运行,调度完成
4、遍历数组queue[140]时间复杂度是常数,但是太低效了
- bitmap[5]一共140个优先级,一共140个进程队列,为了提高查找非空间队列的效率,可以用5*32个比特位表示队列是否为空,这样可以提高查找效率
- 过期队列和活动队列结构一模一样
- 过期队列上放置的进程,都是时间片耗尽的进程
- 当活动队列上的进程都被处理完毕之后,对过期队列的进程时间片重新计算
- active指针永远指向活动队列
- expried指针永远指向过期对列
- 可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时一直都存在的
- 在合适的时候,交换active指针和expried指针的内容,就相当于有了一批新的活跃进程
- 在系统中查找一个最合适调度的进程时间复杂度是一个常数,不随着进程增多而导致时间成本增加,我们称之为进程调度O(1)算法



