生产者-消费者问题也称为有界缓冲区问题。
存在于多进程或多线程下,多个进程或线程读取同一个公共固定大小缓冲区产生的竞争。
参考:生产者-消费者维基百科
一般实现:
存在竞争条件。
消费者读取计数器发现为零,准备sleep(),消费者此刻不是sleep()状态;
进程切换,生产者生产数据放入缓冲区,调用wakeup(),然而消费者此刻不是sleep()状态,信号丢失。
进程切换,消费者调用sleep(),进入睡眠。
生产者一直生产数据放入缓冲区,直到缓冲区满。而消费者一直处于sleep()状态。
信号量(semaphore):
三个信号量:
mutex:此信号量用于互斥,保证一个时刻只有一个进程读写缓冲区和相关变量。初始值为1。
full:表示槽位不为空;初始值为0。
empty:槽位为空;初始值是缓冲区大小。
对信号量的两种操作:down up
注:down 和 up操作是系统调用,通过TSL或XCHG指令来确保同一时刻只有一个cpu对信号量进行操作,可实现原子操作。
对生产者而言:顺序调用down(&empty),up(&full)。即减少一个空槽位,增加一个有数据的槽位。当槽位等于缓冲区大小,睡眠。
对消费者而言:顺序调用down(&full) ,up(&empty) 。即减少一个有数据的槽位,增加一个空槽位。当槽位数为零,睡眠。
其中,读和写操作放在down(&mutex) up(&mutex)之间,这样就可以实现只有一个线程被执行。
down(&mutex)
新数据放入缓冲区/从缓冲区取出数据
up(&mutex)
摘自操作系统:
管程是一个由过程,变量及数据结构等组合成的一个集合,它们组成一个特殊的模块或软件包。
管程有一个很重要的特性,即任一时刻管程中只能有一个活跃进程,这一特性使管程能有效地完成互斥。
管程中采用两个条件变量:wait 和signal 。
当管程发现某个线程无法继续运行(如:生产者发现缓冲区变量),它会在某个条件变量上执行wait操作。
通过signal唤醒正在睡眠的进程。
其中java实现使用的是wait和notifyAll。
对多线程理解的不到位,感觉还是不懂。
附练习的代码。
java实现:(模拟多个生产者和消费者不限制次数运行)
生产者:
/**
* 生产者
* Created by bigliang on 2016/10/6.
*/
public class Producer extends Thread {
String name;
int needNum;
Monitor monitor ;
public Producer(String name, Monitor monitor) {
this.name = name;
this.monitor = monitor;
}
@Override
public void run() {
Random random = new Random(47);
while(true){
needNum = random.nextInt(50)+1;
monitor.produce(name,needNum);}
}
}
/**
* 消费者
* Created by bigliang on 2016/10/6.
*/
public class Consumer extends Thread {
String name;
int needNum;
Monitor monitor;
public Consumer(String name, Monitor monitor) {
this.name = name;
this.monitor = monitor;
}
@Override
public void run() {
Random random = new Random(47);
while(true){
needNum = random.nextInt(50)+1;
monitor.consume(name,needNum);}
}
}
管程:
/**
* 管程
* Created by bigliang on 2016/10/6.
*/
public class Monitor {
public static final int NUM= 100; //定义缓冲区大小的常量
public int count = 0 ; //计数器
/**
*
* @param name 哪一个消费者
* @param size 消费量
*/
public synchronized void consume(String name,int size){
while(size > count ){
System.out.println(name+":消费数量"+size+",大于剩余库存"+count+",无法消费,将进入wait()状态");
try {
wait(); //不满足,等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count = count - size; //满足
System.out.println(name + ":消费" + size + ",目前总量是:" + count);
notifyAll(); //唤醒wait()的线程
}
/**
*
* @param name 哪一个生产者
* @param size 生产量
*/
public synchronized void produce(String name,int size){
while (size + count >= NUM){ //判断是否可以生产
System.out.println(name+":生产数量"+size+",大于可生产数量"+(NUM - count)+",无法生产,将进入wait()状态");
try {
wait(); //不满足条件
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count = count + size; //满足
System.out.println(name+":生产"+size+",目前总量是:"+count);
notifyAll(); //唤醒wait()的线程
}
}
main()函数:
public class Main {
public static void main(String[] args) {
Monitor monitor = new Monitor();
Random random = new Random(47);
Producer p1 = new Producer("生产者1",monitor);
Producer p2 = new Producer("生产者2",monitor);
Producer p3 = new Producer("生产者3",monitor);
Consumer c1 = new Consumer("消费者1",monitor );
Consumer c2 = new Consumer("消费者2",monitor );
Consumer c3 = new Consumer("消费者3",monitor );
Consumer c4 = new Consumer("消费者4",monitor );
Consumer c5 = new Consumer("消费者5",monitor );
Consumer c6 = new Consumer("消费者6",monitor );
Consumer c7 = new Consumer("消费者7",monitor );
Consumer c8 = new Consumer("消费者8",monitor );
Consumer c9 = new Consumer("消费者9",monitor );
p1.start();
p2.start();
p3.start();
c1.start();
c2.start();
c3.start();
c4.start();
c5.start();
c6.start();
c7.start();
c8.start();
c9.start();
}
}
运行结果如下:(截取部分)
生产者2:生产9,目前总量是:9
生产者2:生产6,目前总量是:15
生产者2:生产44,目前总量是:59
生产者2:生产12,目前总量是:71
生产者2:生产12,目前总量是:83
生产者2:生产数量30,大于可生产数量17,无法生产,将进入wait()状态
生产者3:生产9,目前总量是:92
生产者3:生产6,目前总量是:98
生产者3:生产数量44,大于可生产数量2,无法生产,将进入wait()状态
生产者2:生产数量30,大于可生产数量2,无法生产,将进入wait()状态
消费者3:消费9,目前总量是:89
消费者3:消费6,目前总量是:83
消费者3:消费44,目前总量是:39
消费者3:消费12,目前总量是:27
消费者3:消费12,目前总量是:15
消费者3:消费数量30,大于剩余库存15,无法消费,将进入wait()状态
生产者2:生产30,目前总量是:45
生产者2:生产19,目前总量是:64
生产者2:生产1,目前总量是:65
生产者2:生产23,目前总量是:88
生产者2:生产8,目前总量是:96
生产者2:生产数量39,大于可生产数量4,无法生产,将进入wait()状态
消费者7:消费9,目前总量是:87
消费者7:消费6,目前总量是:81
消费者7:消费44,目前总量是:37
消费者7:消费12,目前总量是:25
消费者7:消费12,目前总量是:13
消费者7:消费数量30,大于剩余库存13,无法消费,将进入wait()状态
生产者3:生产44,目前总量是:57
生产者3:生产12,目前总量是:69
生产者3:生产12,目前总量是:81
生产者3:生产数量30,大于可生产数量19,无法生产,将进入wait()状态
消费者7:消费30,目前总量是:51
消费者7:消费19,目前总量是:32
消费者7:消费1,目前总量是:31
消费者7:消费23,目前总量是:8
生产者2:生产39,目前总量是:47
生产者2:生产29,目前总量是:76
生产者2:生产2,目前总量是:78
生产者2:生产数量40,大于可生产数量22,无法生产,将进入wait()状态
消费者3:消费30,目前总量是:48
消费者3:消费19,目前总量是:29
消费者3:消费1,目前总量是:28
消费者3:消费23,目前总量是:5
消费者3:消费数量8,大于剩余库存5,无法消费,将进入wait()状态
生产者2:生产40,目前总量是:45
生产者2:生产10,目前总量是:55
生产者2:生产29,目前总量是:84
生产者2:生产数量49,大于可生产数量16,无法生产,将进入wait()状态
消费者7:消费8,目前总量是:76
消费者7:消费39,目前总量是:37
消费者7:消费29,目前总量是:8
消费者7:消费2,目前总量是:6
消费者7:消费数量40,大于剩余库存6,无法消费,将进入wait()状态
消费者2:消费数量9,大于剩余库存6,无法消费,将进入wait()状态
生产者1:生产9,目前总量是:15
生产者1:生产6,目前总量是:21
生产者1:生产44,目前总量是:65
生产者1:生产12,目前总量是:77
生产者1:生产12,目前总量是:89
生产者1:生产数量30,大于可生产数量11,无法生产,将进入wait()状态
生产者3:生产数量30,大于可生产数量11,无法生产,将进入wait()状态
消费者6:消费9,目前总量是:80
消费者6:消费6,目前总量是:74
消费者6:消费44,目前总量是:30
消费者6:消费12,目前总量是:18
消费者6:消费12,目前总量是:6
消费者6:消费数量30,大于剩余库存6,无法消费,将进入wait()状态
消费者2:消费数量9,大于剩余库存6,无法消费,将进入wait()状态
消费者7:消费数量40,大于剩余库存6,无法消费,将进入wait()状态
生产者2:生产49,目前总量是:55
生产者2:生产12,目前总量是:67
生产者2:生产21,目前总量是:88
生产者2:生产9,目前总量是:97
生产者2:生产数量17,大于可生产数量3,无法生产,将进入wait()状态
消费者3:消费8,目前总量是:89
消费者3:消费39,目前总量是:50
消费者3:消费29,目前总量是:21
消费者3:消费2,目前总量是:19
消费者3:消费数量40,大于剩余库存19,无法消费,将进入wait()状态
生产者2:生产17,目前总量是:36
生产者2:生产41,目前总量是:77
生产者2:生产12,目前总量是:89
生产者2:生产数量23,大于可生产数量11,无法生产,将进入wait()状态
消费者5:消费9,目前总量是:80
消费者5:消费6,目前总量是:74
消费者5:消费44,目前总量是:30
消费者5:消费12,目前总量是:18
消费者5:消费12,目前总量是:6
消费者5:消费数量30,大于剩余库存6,无法消费,将进入wait()状态
消费者1:消费数量9,大于剩余库存6,无法消费,将进入wait()状态
消费者7:消费数量40,大于剩余库存6,无法消费,将进入wait()状态
消费者9:消费数量9,大于剩余库存6,无法消费,将进入wait()状态
消费者2:消费数量9,大于剩余库存6,无法消费,将进入wait()状态
消费者6:消费数量30,大于剩余库存6,无法消费,将进入wait()状态
生产者3:生产30,目前总量是:36
生产者3:生产19,目前总量是:55
生产者3:生产1,目前总量是:56
生产者3:生产23,目前总量是:79
生产者3:生产8,目前总量是:87
生产者3:生产数量39,大于可生产数量13,无法生产,将进入wait()状态
生产者1:生产数量30,大于可生产数量13,无法生产,将进入wait()状态
消费者8:消费9,目前总量是:78
消费者8:消费6,目前总量是:72
消费者8:消费44,目前总量是:28
消费者8:消费12,目前总量是:16
消费者8:消费12,目前总量是:4
消费者8:消费数量30,大于剩余库存4,无法消费,将进入wait()状态
消费者4:消费数量9,大于剩余库存4,无法消费,将进入wait()状态
生产者1:生产30,目前总量是:34
生产者1:生产19,目前总量是:53
生产者1:生产1,目前总量是:54
生产者1:生产23,目前总量是:77
生产者1:生产8,目前总量是:85
生产者1:生产数量39,大于可生产数量15,无法生产,将进入wait()状态
生产者3:生产数量39,大于可生产数量15,无法生产,将进入wait()状态
消费者6:消费30,目前总量是:55
消费者6:消费19,目前总量是:36
消费者6:消费1,目前总量是:35
消费者6:消费23,目前总量是:12
消费者6:消费8,目前总量是:4
消费者6:消费数量39,大于剩余库存4,无法消费,将进入wait()状态
消费者2:消费数量9,大于剩余库存4,无法消费,将进入wait()状态
消费者9:消费数量9,大于剩余库存4,无法消费,将进入wait()状态
消费者7:消费数量40,大于剩余库存4,无法消费,将进入wait()状态
消费者1:消费数量9,大于剩余库存4,无法消费,将进入wait()状态
消费者5:消费数量30,大于剩余库存4,无法消费,将进入wait()状态
生产者2:生产23,目前总量是:27
生产者2:生产5,目前总量是:32
生产者2:生产34,目前总量是:66
生产者2:生产7,目前总量是:73
消费者3:消费40,目前总量是:33
生产者2:生产26,目前总量是:59
生产者2:生产11,目前总量是:70
生产者2:生产数量43,大于可生产数量30,无法生产,将进入wait()状态
消费者5:消费30,目前总量是:40
消费者1:消费9,目前总量是:31
消费者7:消费数量40,大于剩余库存31,无法消费,将进入wait()状态
消费者9:消费9,目前总量是:22
消费者9:消费6,目前总量是:16
消费者9:消费数量44,大于剩余库存16,无法消费,将进入wait()状态
消费者2:消费9,目前总量是:7
消费者2:消费6,目前总量是:1
消费者2:消费数量44,大于剩余库存1,无法消费,将进入wait()状态
消费者6:消费数量39,大于剩余库存1,无法消费,将进入wait()状态
生产者3:生产39,目前总量是:40
生产者3:生产29,目前总量是:69
生产者3:生产2,目前总量是:71
生产者3:生产数量40,大于可生产数量29,无法生产,将进入wait()状态
生产者1:生产数量39,大于可生产数量29,无法生产,将进入wait()状态
消费者4:消费9,目前总量是:62
消费者4:消费6,目前总量是:56
消费者4:消费44,目前总量是:12
消费者4:消费12,目前总量是:0
消费者4:消费数量12,大于剩余库存0,无法消费,将进入wait()状态
消费者8:消费数量30,大于剩余库存0,无法消费,将进入wait()状态
生产者1:生产39,目前总量是:39
生产者1:生产29,目前总量是:68
生产者1:生产2,目前总量是:70
生产者1:生产数量40,大于可生产数量30,无法生产,将进入wait()状态
生产者3:生产数量40,大于可生产数量30,无法生产,将进入wait()状态
消费者6:消费39,目前总量是:31
消费者6:消费29,目前总量是:2
消费者6:消费2,目前总量是:0
消费者6:消费数量40,大于剩余库存0,无法消费,将进入wait()状态
消费者2:消费数量44,大于剩余库存0,无法消费,将进入wait()状态
消费者9:消费数量44,大于剩余库存0,无法消费,将进入wait()状态
消费者7:消费数量40,大于剩余库存0,无法消费,将进入wait()状态
消费者1:消费数量6,大于剩余库存0,无法消费,将进入wait()状态
消费者5:消费数量19,大于剩余库存0,无法消费,将进入wait()状态
生产者2:生产43,目前总量是:43
生产者2:生产25,目前总量是:68
生产者2:生产5,目前总量是:73
生产者2:生产1,目前总量是:74
生产者2:生产数量27,大于可生产数量26,无法生产,将进入wait()状态
消费者3:消费10,目前总量是:64
消费者3:消费29,目前总量是:35
生产者2:生产27,目前总量是:62
生产者2:生产23,目前总量是:85
消费者5:消费19,目前总量是:66
消费者1:消费6,目前总量是:60
消费者7:消费40,目前总量是:20
消费者9:消费数量44,大于剩余库存20,无法消费,将进入wait()状态
消费者2:消费数量44,大于剩余库存20,无法消费,将进入wait()状态
消费者6:消费数量40,大于剩余库存20,无法消费,将进入wait()状态
生产者3:生产40,目前总量是:60
生产者3:生产10,目前总量是:70
生产者3:生产29,目前总量是:99
生产者3:生产数量49,大于可生产数量1,无法生产,将进入wait()状态
生产者1:生产数量40,大于可生产数量1,无法生产,将进入wait()状态
消费者8:消费30,目前总量是:69
消费者8:消费19,目前总量是:50
消费者8:消费1,目前总量是:49
消费者8:消费23,目前总量是:26
消费者8:消费8,目前总量是:18
消费者8:消费数量39,大于剩余库存18,无法消费,将进入wait()状态
消费者4:消费12,目前总量是:6
消费者4:消费数量30,大于剩余库存6,无法消费,将进入wait()状态
消费者8:消费数量39,大于剩余库存6,无法消费,将进入wait()状态
生产者1:生产40,目前总量是:46
生产者1:生产10,目前总量是:56
生产者1:生产29,目前总量是:85
生产者1:生产数量49,大于可生产数量15,无法生产,将进入wait()状态
生产者3:生产数量49,大于可生产数量15,无法生产,将进入wait()状态
消费者6:消费40,目前总量是:45
消费者6:消费10,目前总量是:35
消费者6:消费29,目前总量是:6
消费者6:消费数量49,大于剩余库存6,无法消费,将进入wait()状态
消费者2:消费数量44,大于剩余库存6,无法消费,将进入wait()状态
消费者9:消费数量44,大于剩余库存6,无法消费,将进入wait()状态
消费者7:消费数量10,大于剩余库存6,无法消费,将进入wait()状态
消费者1:消费数量44,大于剩余库存6,无法消费,将进入wait()状态
消费者5:消费1,目前总量是:5
消费者5:消费数量23,大于剩余库存5,无法消费,将进入wait()状态
生产者2:生产47,目前总量是:52
生产者2:生产34,目前总量是:86
生产者2:生产数量35,大于可生产数量14,无法生产,将进入wait()状态
消费者3:消费49,目前总量是:37
消费者3:消费12,目前总量是:25
消费者3:消费21,目前总量是:4
消费者3:消费数量9,大于剩余库存4,无法消费,将进入wait()状态
生产者2:生产35,目前总量是:39
生产者2:生产45,目前总量是:84
消费者5:消费23,目前总量是:61
消费者5:消费8,目前总量是:53
消费者5:消费39,目前总量是:14
消费者5:消费数量29,大于剩余库存14,无法消费,将进入wait()状态
消费者1:消费数量44,大于剩余库存14,无法消费,将进入wait()状态
消费者7:消费10,目前总量是:4
消费者9:消费数量44,大于剩余库存4,无法消费,将进入wait()状态
消费者2:消费数量44,大于剩余库存4,无法消费,将进入wait()状态
消费者6:消费数量49,大于剩余库存4,无法消费,将进入wait()状态
生产者3:生产49,目前总量是:53
生产者3:生产12,目前总量是:65
生产者3:生产21,目前总量是:86
生产者3:生产9,目前总量是:95
生产者3:生产数量17,大于可生产数量5,无法生产,将进入wait()状态
生产者1:生产数量49,大于可生产数量5,无法生产,将进入wait()状态
消费者8:消费39,目前总量是:56
消费者8:消费29,目前总量是:27
消费者8:消费2,目前总量是:25
消费者8:消费数量40,大于剩余库存25,无法消费,将进入wait()状态
消费者4:消费数量30,大于剩余库存25,无法消费,将进入wait()状态
生产者1:生产49,目前总量是:74
生产者3:生产17,目前总量是:91
这里实现是加synchronized关键字。这个就可以保证不会发生竞争混乱的问题。
参考1:http://www.jasongj.com/java/multi_thread/
参考2:http://blog.youkuaiyun.com/monkey_d_meng/article/details/6251879
参考3:生产者-消费者维基百科