进程互斥的软件实现

进程互斥的软件实现方法,以下是详细介绍:

几种软件互斥

单标志法

  • 实现逻辑
    • 在进入区,只进行“检查”操作,不执行“上锁”动作 。通过一个共享变量turn来记录当前允许进入临界区的进程。
    • 在退出区,把临界区的使用权转交给另一个进程,相当于为另一进程“解锁”,同时给自己“上锁”。例如,若进程P0在退出临界区时,将turn设为1,表示现在允许P1进入临界区。
  • 主要问题:不遵循“空闲让进”原则。如果一个进程一直不进入临界区,即使临界区空闲,另一个进程也无法进入。比如P1一直不访问临界区,P0退出后也不能再次进入,导致资源浪费。

双标志先检查法

  • 实现逻辑
    • 在进入区,先检查其他进程是否想进入临界区(通过检查标志位),然后再设置自己的标志位(“上锁” ),表明自己要进入临界区;在退出区则执行“解锁”操作,即把自己的标志位设为表示不进入临界区的状态。
  • 主要问题:不遵循“忙则等待”原则 。由于“检查”和“上锁”不是原子操作,可能出现两个进程都在检查时发现对方不想进入,然后同时设置自己标志位进入临界区的情况,无法保证互斥。

双标志后检查法

  • 实现逻辑
    • 在进入区,先设置自己的标志位(“加锁” ),表明自己想进入临界区,然后再检查其他进程的标志位;在退出区进行“解锁”操作。
  • 主要问题:不遵循“空闲让进”和“有限等待”原则,可能导致“饥饿” 。当两个进程都争着进入临界区时,可能会不断重复设置标志位和检查的过程,谁都无法进入临界区,造成进程长期等待,即“饥饿”现象。

Peterson算法

  • 实现逻辑
    • 在进入区,进程先“主动争取”进入临界区(设置自己的标志位表示想进入 ),然后“主动谦让”(设置一个变量表示愿意把机会让给对方 ),最后检查对方是否想进以及己方是否谦让,根据结果决定是否进入临界区。
  • 主要问题:不遵循“让权等待”原则,会发生“忙等” 。进程在等待进入临界区时,会持续占用CPU资源不断检查条件,而不是释放CPU,造成CPU资源浪费。

代码示例

以下是分别用Java代码实现上述几种进程互斥软件方法的示例:

单标志法

class SingleFlagMethod {
    // 记录允许进入临界区的进程编号,0表示P0,1表示P1
    static int turn = 0; 

    static class Process extends Thread {
        int id; // 进程编号,0或1

        Process(int id) {
            this.id = id;
        }

        @Override
        public void run() {
            while (true) {
                // 进入区
                while (turn != id) {
                    // 等待,不做操作
                }
                // 临界区
                System.out.println("Process " + id + " is in critical section");
                // 退出区
                turn = 1 - id;
                System.out.println("Process " + id + " leaves critical section");
            }
        }
    }

    public static void main(String[] args) {
        Process p0 = new Process(0);
        Process p1 = new Process(1);
        p0.start();
        p1.start();
    }
}

双标志先检查法

class DoubleFlagPreCheckMethod {
    // 标志数组,记录进程是否想进入临界区
    static boolean[] flag = {false, false}; 

    static class Process extends Thread {
        int id; // 进程编号,0或1

        Process(int id) {
            this.id = id;
        }

        @Override
        public void run() {
            while (true) {
                // 进入区
                flag[id] = true;
                while (flag[1 - id]) {
                    // 等待
                }
                // 临界区
                System.out.println("Process " + id + " is in critical section");
                // 退出区
                flag[id] = false;
                System.out.println("Process " + id + " leaves critical section");
            }
        }
    }

    public static void main(String[] args) {
        Process p0 = new Process(0);
        Process p1 = new Process(1);
        p0.start();
        p1.start();
    }
}

双标志后检查法

class DoubleFlagPostCheckMethod {
    // 标志数组,记录进程是否想进入临界区
    static boolean[] flag = {false, false}; 

    static class Process extends Thread {
        int id; // 进程编号,0或1

        Process(int id) {
            this.id = id;
        }

        @Override
        public void run() {
            while (true) {
                // 进入区
                flag[id] = true;
                while (flag[1 - id]) {
                    flag[id] = false;
                    flag[id] = true;
                }
                // 临界区
                System.out.println("Process " + id + " is in critical section");
                // 退出区
                flag[id] = false;
                System.out.println("Process " + id + " leaves critical section");
            }
        }
    }

    public static void main(String[] args) {
        Process p0 = new Process(0);
        Process p1 = new Process(1);
        p0.start();
        p1.start();
    }
}

Peterson算法

class PetersonAlgorithm {
    // 标志数组,记录进程是否想进入临界区
    static boolean[] flag = {false, false}; 
    // 记录谦让的进程编号
    static int turn; 

    static class Process extends Thread {
        int id; // 进程编号,0或1

        Process(int id) {
            this.id = id;
        }

        @Override
        public void run() {
            while (true) {
                // 进入区
                flag[id] = true;
                turn = 1 - id;
                while (flag[1 - id] && turn == 1 - id) {
                    // 等待
                }
                // 临界区
                System.out.println("Process " + id + " is in critical section");
                // 退出区
                flag[id] = false;
                System.out.println("Process " + id + " leaves critical section");
            }
        }
    }

    public static void main(String[] args) {
        Process p0 = new Process(0);
        Process p1 = new Process(1);
        p0.start();
        p1.start();
    }
}

这些代码示例中,每个方法都创建了两个线程来模拟两个进程,通过不同的逻辑来实现进程互斥。但正如前面所述,单标志法、双标志先检查法、双标志后检查法存在各自的缺陷,Peterson算法虽然在一定程度上解决了互斥问题,但存在忙等现象。

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务