Thread yield after mutex unlock?

Is is sensible to unlock a mutex and immediately re-lock it? Consider this example:

  pthread_mutex_lock(mutex);
  while(1) {
      /* Do work. */
      pthread_mutex_unlock(mutex);
      pthread_mutex_lock(mutex);
  }

The intention here is to make other threads wait until we’ve finished doing work. Then we give them a chance to get in before we go round again and do more work. But can we guarantee that the scheduler will allow another thread to get in when we unlock a mutex? Is it possible that this thread will immediately re-lock the mutex, and never give other threads a chance to get in?

If that’s possible, then it would make sense to put an explicit yield between the calls to unlock and then lock:

  pthread_mutex_lock(mutex);
  while(1) {
      /* Do work. */
      pthread_mutex_unlock(mutex);
      sched_yield();
      pthread_mutex_lock(mutex);
  }

So, is the explicit yield necessary, or even desireable? This is what the POSIX standard has to say:

The pthread_mutex_unlock() function shall release the mutex object referenced by mutex… If there are threads blocked on the mutex object referenced by mutex when pthread_mutex_unlock() is called, resulting in the mutex becoming available, the scheduling policy shall determine which thread shall acquire the mutex.

from the Single Unix Spec. IEEE Std 1003.1, 2004

This says that a call to unlock() must cause the scheduler to re-consider which thread to run. That guarantees another thread waiting on the mutex the chance to get in.

Experimentation (on HP-UX, Linux, Tru64, OSX and AIX) shows that the explicit yield() is never needed. Indeed it sometimes has a dramatically adverse affect on performance. On Linux, OSX and AIX, a thread which yields gets up to 10,000 times less CPU time than a thread that does not yield!

Leave a Comment

Sponsors