从linux进程机制到TopwiseProp的分析

来源:互联网 发布:本科做网络维护 编辑:程序博客网 时间:2024/06/03 21:36

在linux中,如果需要创建一个新的进程,会调用fork()孙数。
我们先来看一段代码:

#include "stdio.h"#include "sys/types.h"#include "unistd.h"int main(){  pid_t p1;  pid_t p2;  p1=fork();//----(1)  p2=fork();//----(2)  printf("p1 id is %d , p2  id is %d \n",p1,p2);}

这段代码的输出为:

p1 id is 31763 , p2  id is 31764 p1 id is 0 , p2  id is 31765 p1 id is 0 , p2  id is 0 p1 id is 31763 , p2  id is 0 

这里有四个输出,原因是因为有四个进程在跑,其中三个是当前进程的子进程。

这是由于fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,这其中还包括了PC-程序计数器。
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中。

关于linux进程机制:
1、进程可以看做程序的一次执行过程。在linux下,每个进程有唯一的PID标识进程。
PID是一个从1到32768的正整数,其中1一般是特殊进程init,其它进程从2开始依次编号。当用完32768后,从2重新开始。

2、linux中有一个叫进程表的结构用来存储当前正在运行的进程。
可以使用“ps aux”命令查看所有正在运行的进程。

3、进程在linux中呈树状结构,init为根节点,其它进程均有父进程,
某进程的父进程就是启动这个进程的进程,这个进程叫做父进程的子进程。

4、fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)
数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程

我们先来看为什么会有4个进程:
1、从当前进程P来看,执行到(1)时,产生了第一个子进程pid 为 31763, 执行到(2)时,产生了第二个子进程pid 为 31764
 
 2、进程31763:由于子进程继承了父进程的所有数据,包换程序计数器。这样进程31763 会从(2)开始执行,所以进程31763又调用了一次fork(),产生了一个子进程31765
 
3、进程31764 : 在父进程执行到(2)产生了该进程,所以他紧接着执行后面的输出。不会再产生新的进程。

所以包括父进程在内,共有4个进程。

fork()函数的一个特点是,一次调用,两次返回。一次返回在调用进程中,返回的是新建进程的进程号。另一次返回在子进程中,返回的是0。

这样我们来看输出的结果:
1、在当前进程(父进程)中:调用了两次fork(),返回了两个子进程的id:p1 id is 31763 , p2 id is 31764
2、在子进程31763中:父进程在第一次调用fork()时产生自己,所以此时返回为0,第二次调用fork()即执行(2)时,自己又产生了另一个进程31765,所以有p2=31765。
所以,最终输出为:p1 id is 0 , p2 id is 31765
3、在子进程31764中,由于此时是执行第二个fork()即(2)中,父进程产生了自己,所以p2=0,但是此时p1已经在父进程中被赋值为31763。
所以,最终输出为:p1 id is 31763 , p2 id is 0
4、在子进程31765中:这个进程的父进程是31763,此时在31763进程中第一个fork()是返回0的。于是有p1=0。31763进程在第二个fork()时产生了子进程31765,所以此时的返回值为0。
所以,最终输出为:p1 id is 0 , p2 id is 0

至于这几个进程的执行顺序,则由系统调度来决定,执行顺序是不一定的。

TopwiseProp类

公司为了解决方案公司客户众多,需求各异的情况。没有直接使用build.prop来配置客户需求开关,而是使用了一个TopwiseProp的类。
这个类被放在了idh.code/frameworks/base/core/java/android/os/TopwiseProp.java中。
该文件采用了一个延后加载的方法,即在调用相关方法后,才进行初始化的动作。其中,为了避免多次加载配置文件所带来的性能问题,加入了一个判断:

    private static Properties properties = null;        if (properties == null) {            File oemFile = new File(defSettingPath);            FileInputStream stream = null;            try {                stream = new FileInputStream(oemFile);                InputStreamReader in=new InputStreamReader(stream,"utf-8");                BufferedReader br = new BufferedReader(in);                properties = new Properties();                properties.load(br);            } catch (Exception e) {                // TODO: handle exception                properties=null;            }finally{                if(stream != null){                    try {                        stream.close();                    } catch (IOException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                }            }

  这段代码的本意是在properties未被初始化的情况下进行加载文件的操作。
  由于TopwiseProp只是一个工具类,所以它本身是在进行调用时加载,因而每个进程调用时(properties == null)都是成立的。从而每个进程都会加载一次配置文件。
  
但实际结果却发现是,只有第一个进程调用时会加载配置文件,后续的进程调用不会再进行加载操作。从而达到了在一次开机后,该文件加载操作仅会执行一次。

虽然这可能并非设计者的本意,但却达到了超过设计者预期的效果。

从log分析中,我发现第一次调用该类的进程为zygote。
我们知道在进程号为1的init进程在创建完zygote后,把后续创建进程的任务交给了zygote。
这样一来,以后的android进程都是zygote的子进程。
所以后续的进程实际上都会把TopwiseProp实例拷贝一份在自己的进程里。所以才达到了这种一次加载,多进程共同使用结果的效果。

0 0
原创粉丝点击