You have to use the same mutex when the¬†in()¬†thread sets¬†isEmpty = false¬†and the¬†out()thread tests¬†while (isEmpty). Otherwise, this can happen:
- out()¬†thread tests¬†isEmpty, finds it is true;
- in()¬†thread sets¬†isEmpty¬†to false and signals the condition variable (but no-one wakes up, beacuse no-one is waiting yet);
- out()¬†thread calls¬†cond.wait()¬†and blocks forever, despite the fact that the queue is not empty anymore.
Note that in this sequence there hasn't been a spurious wakeup - it's just a plain old race condition.
As long as you update¬†isEmpty¬†with the same mutex held as when you test¬†isEmpty, this interleaving can't happen.