There's a name for that problem. It's called starvation, and it often can be a problem when any thread keeps a mutex locked for an extended period of time. Each of the two threads in your example tries to keep the mutex locked all the time. (Yeah, they unlock the mutex each time around the loop, but then they re-lock it in the very next instruction.)
The best way to fix starvation is, don't keep the mutex locked any longer than necessary. One of the threads in your example calls sleep()
while the mutex is locked. That is virtually always a bad idea in any real program.
Another way to fix it is to use a so-called "fair" mutex. Ownership of a fair mutex always is awarded to the thread that's been waiting the longest. It's less efficient than the regular kind of mutex, but it can be an easy fix for some starvation problems. Unfortunately, there may not be any standard way (or any way at all) to get a fair mutex on any given platform.
FYI: What happens in your example is, Thread 1 wakes up from the sleep()
call and releases the mutex. As soon as the mutex is released, it's a race between the two threads to see which one will get it next. Unfortunately, thread 2 was blocked awaiting the mutex when the gun went off. The OS moves thread 2 to a "run queue" where it must wait for a CPU to run on. Meanwhile, thread 1 is already running. Thread 1 grabs the mutex again, then thread 2 wakes up soon after, finds the mutex locked, and goes back to waiting.