Question

I'm trying to use mutex instead of semaphore because I want semaphore behavior but binary (not counting). (Perhaps you'll notice I'm in the early stages of trying to simulate the Sleeping Barber algorithm.) This is my code:

#include <stdio.h>
#include <pthread.h>

int main( int argc, char** argv ) {

  int freeSeats = 6;

  pthread_mutexattr_t mutexAttr;
  pthread_mutex_t custWaiting, wrAccess, barberReady;

  pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);

  pthread_mutex_init(&custWaiting, &mutexAttr);
  pthread_mutex_init(&wrAccess, &mutexAttr);
  pthread_mutex_init(&barberReady, &mutexAttr);

  pthread_mutex_lock(&custWaiting);
  pthread_mutex_lock(&custWaiting);
  pthread_mutex_lock(&custWaiting);

  fprintf(stdout, "got here\n\n");

  return 0;

}

When I execute for the first time, this runs as expected (thread is blocked, command line hangs while my program waits to be able to lock). When I kill the program, and run it a second time, it prints "got here", which it should not. Why would this only fail on the second (and all following) attempts, but not on the first?

Bafflingly, if I modify the code as follows (only the init and lock lines):

#include <stdio.h>
#include <pthread.h>

int main( int argc, char** argv ) {

  int freeSeats = 6;

  pthread_mutexattr_t mutexAttr;
  pthread_mutex_t custWaiting, wrAccess, barberReady;

  pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);

  int y = pthread_mutex_init(&custWaiting, &mutexAttr);
  y = pthread_mutex_init(&wrAccess, &mutexAttr);
  y = pthread_mutex_init(&barberReady, &mutexAttr);

  int x = pthread_mutex_lock(&custWaiting);
  x = pthread_mutex_lock(&custWaiting);
  x = pthread_mutex_lock(&custWaiting);

  fprintf(stdout, "got here\n\n");

  return 0;

}

... then it works every time. The reason this is so maddening is because I can't check error codes on pthread_mutex_whatever() because it doesn't fail when I try to catch the error codes. I don't want to assign the return values to ints if I'm not going to use them. As you can see, I'm not using x or y at all; just assigning return values of init and lock functions to them. So why does that change the behavior of the mutexes so drastically? Or am I missing something else? What am I doing wrong?

Was it helpful?

Solution

You should init your mutexattr by calling :

pthread_mutexattr_init(&mutexAttr);

And also set the type :

pthread_mutexattr_settype(amutexAttr, PTHREAD_MUTEX_NORMAL);

otherwise your code depends on the stack content, and the mutex can be of recursive type, which is why you see random behaviour. If you set the type to PTHREAD_MUTEX_DEFAULT, behaviour is undefined, while PTHREAD_MUTEX_NORMAL gives you deadlock

OTHER TIPS

You are taking the lock on the same mutex three times, this is undefined behavior unless you declare your mutex to be recursive. Probably you meant to lock the three different mutexes.

The undefined behavior means that anything can happen, including the behavior that you observe, here.

To set the properties of a mutex, you'd have to change the properties of the mutex attribute with pthread_mutexattr_settype. There are basically two types that augment the default behavior, PTHREAD_MUTEX_ERRORCHECK and PTHREAD_MUTEX_RECURSIVE. The first would block if you try to re-lock, the second can be used to lock and unlock multiple times.

The default behavior is leaving this undefined, because implementing such checks are costly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top