Preventing multiple threads from racing on a queue while not wastefully polling its size
You wouldn't have just your queue and your semaphore. You would also have a global atomic variable where "false" means "I can guarantee one hundred percent that there is no data in the queue", and "true" means "There is probably some data in the queue, but maybe not". 

Any code that modifies the queue would very carefully update the global variable. You need an operating system that makes it possible that code using locking can change such a variable as you need it. 

For some interesting reading, google for "dispatch_once implementation".