Стандартный способ реализации Producer Consumer:
useQueue
мьютекс
emptyCount
семафор размером N
fullCount
семафор размером N
продукты:
down(emptyCount)
down(useQueue)
putItemIntoQueue(item)
up(useQueue)
up(fullCount)
потреблять:
down(fullCount)
down(useQueue)
item ← getItemFromQueue()
up(useQueue)
up(emptyCount)
Где, если down
имеет неположительное значение, поток ожидает.
up
увеличивает счет
Взято из этой статьи в Википедии
Почему у нас не может быть что-то вроде:
class NewSemaphore {
int capacity, permits;
/**
* Initialize the semaphore with a max capacity
* @param n the max capacity
*/
NewSemaphore(int n) {
capacity = n;
permits = 0;
}
/**
* We usually never check this. Check if it's within limits.
* If not, wait
*/
synchronized void up() {
if (permits >= capacity) {
wait();
} else {
permits++;
notify();
}
}
/**
* Standard down/acquire function
*/
synchronized void down() {
if (permits <= 0) {
wait();
} else {
permits--;
notify();
}
}
}
Это будет называться как:
продукция:
up(mySemaphore)
down(useQueue)
putItemIntoQueue(item)
up(useQueue)
потреблять:
down(mySemaphore)
down(useQueue)
item ← getItemFromQueue()
up(useQueue)
Зачем нам нужны 2 разные переменные emptyCount
и fullCount
?