为什么生产者消费者代码不起作用?

huangapple go评论73阅读模式
英文:

Why Producer-Consumer code is not working?

问题

以下是您提供的代码的翻译部分:

我正在尝试使用信号量解决生产者-消费者问题
以下是我编写的代码在执行后在生产一个数字后就停止运行

我已经检查了信号量的分配看起来是正确的
调用的acquire和release方法的顺序也看起来是正确的

public class Q {
    int n;
    Semaphore consumerSem = new Semaphore(0);
    Semaphore producerSem = new Semaphore(1);

    synchronized void get(){
        try {
            consumerSem.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Got Data : " + n);
        producerSem.release();
    }

    synchronized void put(int n){
        try {
            producerSem.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Putting Data : " + n);
        this.n=n;
        consumerSem.release();
    }
}

public class Producer implements Runnable{
    Q q;

    Producer(Q q){
        this.q = q;
    }

    @Override
    public void run() {
        for (int i=0; i<20;i++){
            q.put(i);
        }
    }
}

public class Consumer implements Runnable{
    Q q;

    Consumer(Q q){
        this.q = q;
    }

    @Override
    public void run() {
           for (int i =0;i<20;i++){
               q.get();
           }
    }
}

public class PCRun {

    public static void main(String[] args) {
        Q q = new Q();
        new Thread(new Producer(q),"Producer").start();
        new Thread(new Consumer(q),"Consumer").start();
    }
}

请注意,由于您要求只返回翻译后的内容,我已经删除了任何其他的回答或附加信息。如果您有关于这段代码的问题或需要进一步的帮助,请随时提问。

英文:

I am trying to code solution of Producer-Consumer problem with the help of Semaphores.
Below is the code I have written, on execution it is getting stuck after producing one number.

I have checked the assignment of both the Semaphore and it look fine.
The sequence of acquire and release methods being called also looks correct.

public class Q {
int n;
Semaphore consumerSem = new Semaphore(0);
Semaphore producerSem = new Semaphore(1);
synchronized void get(){
try {
consumerSem.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(&quot;Got Data : &quot; + n);
producerSem.release();
}
synchronized void put(int n){
try {
producerSem.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(&quot;Putting Data : &quot; + n);
this.n=n;
consumerSem.release();
}
}
public class Producer implements Runnable{
Q q;
Producer(Q q){
this.q = q;
}
@Override
public void run() {
for (int i=0; i&lt;20;i++){
q.put(i);
}
}
}
public class Consumer implements Runnable{
Q q;
Consumer(Q q){
this.q = q;
}
@Override
public void run() {
for (int i =0;i&lt;20;i++){
q.get();
}
}
}
public class PCRun {
public static void main(String[] args) {
Q q = new Q();
new Thread(new Producer(q),&quot;Producer&quot;).start();
new Thread(new Consumer(q),&quot;Consumer&quot;).start();
}
}

答案1

得分: 1

你已经将getput两个方法进行了同步。因此,生产者进入后会锁定q,使用了producerSem的一个许可,在下一次put调用时会被阻塞。不幸的是,q仍然被生产者锁定,因此消费者无法进入get方法。为了修复这个问题,请移除两个Synchronized关键字。

现在,为了同步对n的访问,在访问n的地方使用synchronized关键字,而不是整个方法。

    int n;
    final Semaphore consumerSem = new Semaphore(0);
    final Semaphore producerSem = new Semaphore(1);

    void get() {
        try {
            consumerSem.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (this) {
            System.out.println("获取数据:" + n);
        }
        producerSem.release();
    }

    void put(int n) {
        try {
            producerSem.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (this) { // 不变式:打印 + 写入,原子操作
            System.out.println("放置数据:" + n);
            this.n = n;
        }
        consumerSem.release();
    }
英文:

You've made get and put synchronized. So the producer goes in, locks q, uses the one permit of producerSem and blocks at the next put call. Unfortunately, q is still locked by the producer, so the consumer won't be able to enter get. To fix this, remove both synchronizeds.

Now to synchronize the access on n, use synchronized only where n is accessed, not for both whole methods.

    int n;
    final Semaphore consumerSem = new Semaphore(0);
    final Semaphore producerSem = new Semaphore(1);

    void get() {
        try {
            consumerSem.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (this) {
            System.out.println(&quot;Got Data : &quot; + n);
        }
        producerSem.release();
    }

    void put(int n) {
        try {
            producerSem.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (this) { // invariant print + write, atomic
            System.out.println(&quot;Putting Data : &quot; + n);
            this.n = n;
        }
        consumerSem.release();
    }

答案2

得分: 0

代替使用2个信号量,只使用1个。变量n的值最终将在2个线程之间共享,因此它是唯一需要同步的内容,因为信号量在本质上是线程安全的。

    public static class Q {

        int n;

        Semaphore available = new Semaphore(0);

        void get() throws InterruptedException {
            available.acquire();
            synchronized (this) {
                System.out.printf("获取 %s\n", n);
            }
        }

        void put(int n){
            available.release();
            synchronized (this) {
                System.out.printf("放置 %s\n", n);
                this.n = n;
            }
        }
    }
英文:

Instead of using 2 semaphores, only use 1. The value of n will ultimately be shared among 2 threads so it's the only thing that needs to be synchronized because Semaphores are inherently thread-safe.

    public static class Q {

        int n;

        Semaphore available = new Semaphore(0);

        void get() throws InterruptedException {
            available.acquire();
            synchronized (this) {
                System.out.printf(&quot;Get %s\n&quot;, n));
            }
        }

        void put(int n){
            available.release();
            synchronized (this) {
                System.out.printf(&quot;Put %s\n&quot;, n);
                this.n = n;
            }
        }
    }

huangapple
  • 本文由 发表于 2020年8月29日 23:52:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/63648941.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定