Using semaphores to achieve producer and consumer issues with limited buffers