操作系统原理之Unix/Linux进程标识符pid管理探索

来源:互联网 发布:steam网络不稳定 编辑:程序博客网 时间:2024/04/28 06:54

操作系统作为整个计算机系统的资源管理者,担任着有序而高效管理计算机资源的艰巨任务。操作系统资源管理的基本对象是进程,为了方便系统的管理,每一个进程需要一个进程标识符pid,这和国家为每一个居民编一个居民身份证号的目的完全一样。

在Unix/Linux中,进程标识符pid是一个16位的整数,它被顺序编号,最小号为0,最大号为32767,闲置的pid可重新使用。详见Unix源代码中的struct poc{……short p_pid;……}《Unix结构分析:核心代码的结构和算法(修订版)》168页。那么,如何有序而高效地管理这32768个pid呢?

本文就此问题探索一下。

(1)标志位法

此方法为每一个pid设置一个使用标志,具体实现时将pid定义为一个二维数组short[][] pid,数组初始化为pid = new short[32768][2],数组的第一维按序存放0~32767个pid,数组的第二维为空闲标志,空闲置0,使用置1。分配时,从标志是0的pid中分配一个给进程,并将其空闲标志置1,回收时只需要将相应pid的空闲标志置0即可。此方法占用的内存空间是32768*2*2B=131072B。此法内存开销较大,标志位中的16位只使用了一位,资源浪费严重。

(2)符号位法

考虑到定义pid的short类型中pid只使用了除符号位以外的低15位,最高位,即符号位未用,因此可以加以利用。具体实现时将pid定义为一维数组short[] pid,数组初始化为pid = new short[32758],按序存放0~32767个pid,符号位是空闲标志,空闲时pid大于0,就表示pid本身,使用时只需将pid取反。分配时,从值大于0的pid中分配一个给进程,并且将其符号位取反,回收时只需在数组中找到绝对值等于要回收的pid,并将其符号位取反即可。此方法占用的内存空间是32768*2B=65536B,相对于第一种方法,节省一半的内存空间。

(3)位示图法,位示图中'0'表示空闲,‘1’表示使用。

32768个pid共需要32768位,即1024个int类型的数据,数组下标是0~1023,设每个int数据的位编号是0~31,则index是i,编号是j位对应的pid=i*32+j。那么,对于一个int,如何判断其j位是1呢?方法是将int类型数据右移j位,再按位&1,如果结果是1,则其j位是1,否则是0。申请和释放是分别需要一个数组来修改位示图,具体见下文程序。此方法占用的内存空间是1024*4B+32*2*4B=4352B,仅仅是符号法的1/15,因此Unix/Linux进程标识符pid管理的优秀方法是位示图法。

基于以上探索,本文用Java来实现进程标识符pid的管理,源代码如下。

// Linux进程标识符pid管理之位示图法,位示图中'0'表示空闲,‘1’表示使用

public class LinuxPidByBitMap {

    private int[] mpid = null;//位示图数组

    private int[] apply = null;//申请进程标识符pid的数组

    private short pid; // 进程标识符pid

    private int[] release = null;//释放进程标识符pid的数组

 

    /**

     * 构造函数,数组初始化。

     */

    public LinuxPidByBitMap() {

        mpid = newint[1024];

        int i;

        for (i = 0;i <mpid.length;i++)

            mpid[i] = 0x00000000;

        mpid[0] = 0x00000001; // 0pid为系统进程使用

        apply = newint[] { 0x00000001,0x00000003, 0x00000007, 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F,

                0x000000FF, 0x000001FF, 0x000003FF,0x000007FF, 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF,

                0x0000FFFF, 0x0001FFFF, 0x0003FFFF,0x0007FFFF, 0x000FFFFF, 0x001FFFFF, 0x003FFFFF, 0x007FFFFF,

                0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF,0x07FFFFFF, 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF,

                0xFFFFFFFF }; // 用于申请pid的数组

        release = newint[] { 0xFFFFFFFE,0xFFFFFFFD, 0xFFFFFFFB, 0xFFFFFFF7, 0xFFFFFFEF, 0xFFFFFFDF, 0xFFFFFFBF,

                0xFFFFFF7F, 0xFFFFFEFF, 0xFFFFFDFF,0xFFFFFBFF, 0xFFFFF7FF, 0xFFFFEFFF, 0xFFFFDFFF, 0xFFFFBFFF,

                0xFFFF7FFF, 0xFFFEFFFF, 0xFFFDFFFF,0xFFFBFFFF, 0xFFF7FFFF, 0xFFEFFFFF, 0xFFDFFFFF, 0xFFBFFFFF,

                0xFF7FFFFF, 0xFEFFFFFF, 0xFDFFFFFF,0xFBFFFFFF, 0xF7FFFFFF, 0xEFFFFFFF, 0xDFFFFFFF, 0xBFFFFFFF,

                0x7FFFFFFF }; // 用于释放pid的数组

    }

 

    /**

     * 获取申请到的进程标识符pid,临界资源,同步互斥访问。

     *

     * @return申请到的进程标识符pid

     */

    public synchronized short getPid() {

        return this.pid;

    }

 

    /**

     * 向系统申请一个空闲进程标识符pid,临界资源,同步互斥访问。

     */

    public synchronized void appllyPid() {

        int i, j;

        for (i = 0;i <mpid.length;i++)

            for (j = 0;j < 32;j++) {

                if (((mpid[i] >>j) & 1) == 0) {

                    mpid[i] =mpid[i] |apply[j];//修改位示图相应位为1

                    pid = (short) (i * 32 +j);//生成进程标识符pid

                    return;

                }

            }

    }

 

    /**

     * 释放一个进程标识符pid,临界资源,同步互斥访问。

     */

    public synchronized void releasePid(shortpid) {

        int i, j;

        i = pid / 32;

        j = pid % 32;

        mpid[i] =mpid[i] &release[j];//修改位示图相应位为0

    }

 

    /**

     * 遍历位示图数组,临界资源,同步互斥访问。

     */

    public synchronized String traversal() {

        int i;

        String temp = new String();

        for (i = 0;i < 4;i++)//由于可视化时,空间有限,只显示前96

            temp += mpid[i] + "    ";

        return temp;

    }

}

1 0