Let's have one or more (N) factories, one storage for all factories with capacity to store L units of products of factories (for ex. cars). Then we have M customers coming to buy a car from the factory storage (random times).
If storage is empty customers go to a waiting for a car queue. If the storage is full, a factory producing a new car goes waiting for a storage space queue. If we have at least one car in the storage the first customer can go in and buy a car. If we have at least one free space for a car the first waiting factory can place the car in the storage.
OS provides system calls called semaphore operations (name comes from rail roads). One semaphore operation, we can call it P, stops a running process, if a condition is not met (for ex. we have not an empty space for a new produced car). An other semaphore operation signals the system (for ex. I did take a car, now we have one more free space, we call it V.
How to build up N producer tasks and M consumer tasks?
In every of producer tasks we have a construction as:
P(empty_space);//OS stops us if no space, we continue when space exist
V(car_available);//We inform OS to start a possibly waiting consumer
In every consumer tasks we have a code as:
P(car_availabe);//OS stops us if no cars
We have some kind of key (name) when a task asks from OS a semaphore common to many tasks.
The semaphores must be initialized as needed for ex. car_available=0, empty_space=L. We tell by an initialization system call to the OS how we want to behave. After that OS takes care that everything goes right (stopping and starting tasks as needed).