进程同步--生产者消费者问题(Producer-consumer Problem)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a1158375969/article/details/78654133

简述:

描述了生产者-消费者问题, 使用java代码重现了较为难以理解的问题, 根据机器代码执行和CPU调度原理分析问题出现的原因.

From Wikipedia

生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了共享固定大小缓冲区的两个线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

Java code

public class MultiThread {
    //多个线程共享这一个变量
    private static int counter = 0;
    //最大的尺寸
    private static final int AMX_SIZE=5;

   static class Consumer implements Runnable{

        @Override
        public void run() {
            while(true){
                while (counter ==0){
                    //System.out.println("c empty");
                }
                counter -= 1;
                System.out.println("     c counter="+ counter);
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static class Producer implements Runnable{

        @Override
        public void run() {
            while(true){
                while (counter ==AMX_SIZE){
                    //System.out.println("p full");
                }
                counter += 1;
                System.out.println("p counter="+ counter);
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        new Thread(new Consumer()).start();
        new Thread(new Producer()).start();
    }
}

分析:
这样的代码看似解决了问题, 但是实际上还隐含有问题, 问题在对于itemCount改变的代码.
首先, 考虑java代码的机器代码如下:

//假定现在counter = 5
//counter++的机器代码
step A1: register1 = counter
step B1: register1 = register1 + 1
step C1: counter = register1

//counter--的机器代码
step A2: register2 = counter
step B2: register2 = register2 - 1
step C2: counter = register2

现在, 我们需要求得有多少种执行可能顺序, 这个问题转化为:

已知有A1B1C1和A2B2C2两个有序数组, 现在求他们的全排列, 要求是他们的排列中, 两个数组仍然有序.

其中一种情况如下所示:

execute step A1: register1 = counter               {counter = 5}
execute step B1: register1 = register1 + 1         {counter = 6}
execute step A2: register2 = counter               {counter = 5}
execute step B2: register2 = register2 - 1         {counter = 4}
execute step C1: counter = register1               {counter = 6}
execute step C2: counter = register2               {counter = 4}

显然与要求违背.

总结:
这仅仅是一行代码的临界区问题就出现了容易忽视的问题, 说明多线程编程有难度, 但是他却很有必要.

展开阅读全文

没有更多推荐了,返回首页