生产者-消费者问题

来源:互联网 发布:使命召唤8 mac 迅雷 编辑:程序博客网 时间:2024/06/14 19:40

生产者/消费者问题

Producer/Consumer problem

  • 概念
  • Java实现
  • Python实现
  • 总结

概念

生产者-消费者(Producer-Consumer)问题是一个著名的进程/线程的同步问题。
- 它描述的是:有一群生产者在生产产品,并将这些产品提供给消费者去消费
- 为了使生产者与消费者能并发执行,在两者之间设置了一个具有n个缓冲区的缓冲池
【生产者】将生产的产品放入缓冲区中;不允许生产者向一个已装满产品的缓冲区投放产品
【消费者】从缓冲区中取走产品去消费;不允许消费者到一个空缓冲区去取产品
- 所有的生产者和消费者进程或线程都是以异步的方式运行的,但它们之间必须保持同步

Java实现

  • 产品类
public class Product {    private long randID;    // 随机ID    public Product(long id) {        this.randID = id;    }    public long getRandID() {        return randID;    }    public void setRandID(long randID) {        this.randID = randID;    }}
  • 消费者类
import java.util.concurrent.Semaphore;public class Consumer implements Runnable {    private java.util.concurrent.ConcurrentLinkedQueue<Product> q;    private Semaphore semaphore;    private String name;    public Consumer(String name,            java.util.concurrent.ConcurrentLinkedQueue<Product> q,            Semaphore semaphore) {        this.name = name;        this.q = q;        this.semaphore = semaphore;    }    public void consume() throws InterruptedException {        semaphore.acquire();        if (q.size() > 0) {            Product product = this.q.remove();            System.out.println("Consumer ["+this.name+            "] notify : consumed product num is " + product.getRandID() + "\n");        }    }    @Override    public void run() {        while (true) {            // 1.延时2秒            try {                Thread.sleep(2000);            } catch (InterruptedException e) {                e.printStackTrace();            }            // 2.消费一个            try {                this.consume();            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}
  • 生产者类
import java.util.concurrent.Semaphore;public class Producer implements Runnable {    private java.util.concurrent.ConcurrentLinkedQueue<Product> q;    private Semaphore semaphore;    private int MAX_AVAILABLE;    private String name;    public Producer(String name, int MAX_AVAILABLE,             java.util.concurrent.ConcurrentLinkedQueue<Product> q,            Semaphore semaphore) {        this.name = name;        this.MAX_AVAILABLE = MAX_AVAILABLE;        this.q = q;        this.semaphore = semaphore;    }    public void produce() {        if (q.size() < MAX_AVAILABLE) {//          long id = System.currentTimeMillis();            long id = (long) (Math.random() * 100);            this.q.add(new Product(id));            System.out.println("Producer ["+this.name                    +"] notify : produced product num is "+id);        }        semaphore.release();    }    @Override    public void run() {        while (true) {            // 1.延时1秒            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }            // 2.生产一个            produce();        }    }}
  • 测试类
import java.util.concurrent.Semaphore;public class Main {    private final static int MAX_AVAILABLE = 5;    public static void main(String[] args) throws InterruptedException {        java.util.concurrent.ConcurrentLinkedQueue<Product> q =                 new java.util.concurrent.ConcurrentLinkedQueue<Product>();        Semaphore semaphore = new Semaphore(0);        Thread produceThread = new Thread(new Producer("p1", MAX_AVAILABLE, q, semaphore));        Thread consumeThread = new Thread(new Consumer("c1", q, semaphore));        produceThread.start();        consumeThread.start();        produceThread.join();        consumeThread.join();    }}

Python实现

  • 生产者和消费者
import threadingimport timeimport random# 通过信号量进行同步semaphore = threading.Semaphore(0)  # 初始信号量为0def consumer(): # 消费者    print("Consumer is waiting.")    ## Acquire a semaphore    semaphore.acquire()  # 当信号量为0时,acquire会阻塞    ## The consumer have access to the shared resource    print("\tConsumer notify : consumed item number %s" % (item,))def producer(): # 生产者    global item    time.sleep(2)    ## Create a random item    item = random.randint(0, 1000)    print("\tProducer notify : produced item number %s" % (item,))    ## Release a semaphore, increamenting the internal counter by one    semaphore.release()  # 信号量 0 -> 1
  • 测试
if __name__ == '__main__':    for i in range(0, 5):        t1 = threading.Thread(target=producer)        t2 = threading.Thread(target=consumer)        t1.start()        t2.start()        t1.join()        t2.join()    print("program terminated")

总结

生产者和消费者问题的实现可以多种多样,同样的,问题的描述也可以多种多样,例如火车入站,对于一条站台轨道,多辆火车如何分配。这类问题都可以总结为对临界资源(Critical Resouce)的管理问题。

其中为实现进程互斥的进入临界区,多采用软件方法,同步机制均遵循下面4条准则:
1. 空闲让进。当无进程处于临界区时,应允许一个请求进入临界区的进程进入临界区,以有效地利用临界资源。
2. 忙则等待。当已有进程进入临界区时,因而其他试图进入临界区的进程必须等待,以保证对临界资源的互斥访问。
3. 有限等待。对要求访问临界资源的进程,应保证在有限时间内能进入自己的临界区,以免陷入死等状态。
4. 让权等待。当进程不能进入自己的临界区时,应立即释放处理机,以免进程陷入忙等状态。

原创粉丝点击