Search code examples
cpthreadsposixmutexshared-memory

Robust mutex not working with shared memory


I'm using an implementation of a memory shared mutex found here: https://gist.github.com/yamnikov-oleg/abf61cf96b4867cbf72d

I was concerned of the behavior of the ownership of the mutex if a process, who has a hold of the lock, crashes. From my testing it seems that the other processes will not be able to get the lock. I found the concept of robust mutexes while searching, and modified the code by altering this portion:

  // If shared memory was just initialized -
  // initialize the mutex as well.
  if (mutex.created) {
    pthread_mutexattr_t attr;
    if (pthread_mutexattr_init(&attr)) {
      perror("pthread_mutexattr_init");
      return mutex;
    }
    if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) {
      perror("pthread_mutexattr_setpshared");
      return mutex;
    }
    if (pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST)) { //Added this portion.
      perror("pthread_mutexattr_setrobust");
      return mutex;
    }
    if (pthread_mutex_init(mutex_ptr, &attr)) {
      perror("pthread_mutex_init");
      return mutex;
    }
  }

The code which is using these files is:

  shared_mutex_t mutex = shared_mutex_init("/my-mutex");

  if (mutex.ptr == NULL) return 1;

  if (mutex.created) printf("The mutex was just created\n");
  int i = 0;
  while(1) {
    int trylock = pthread_mutex_trylock(mutex.ptr);
    printf("Try lock: %d\n", trylock);
    if (trylock != 0) continue;

    printf("I'm in\n");

    if (i == 5) {
      return 1 / 0;
    }

    sleep(5);    
    pthread_mutex_unlock(mutex.ptr);
    sleep(1);

    i++;
    if (i == 10) {
      break;
    }
  }

For testing, I run two instances of the program and observe the lock ownership being passed between them. When i == 5, the program will break and the ownership should be passed for the next call to lock, from what I've read of robust mutexes.

But, it seems that nothing changed and the behavior is the same as before I altered anything. Any ideas of how to proceed? Thanks in advance.

Edit:

Using pthread_mutex_trylock gives the correct behavior to the program. It seems that the "my-mutex" file that is created in /dev/shm was holding the instance of the mutex I was using in previous attempts, which did not include the robust setting I later altered. Deleting it and running with the aforementined function makes it return OWNERDEAD and the process is able to lock the mutex.


Solution

  • Documentation says:

    The mutex object referenced by mutex shall be locked by a call to pthread_mutex_lock() that returns zero or [EOWNERDEAD].

    You are not handling [OWNERDEAD] return code properly, so you are missing the re-locking of the mutex.

    More about how this should be handled:

    If mutex is a robust mutex and the owning thread terminated while holding the mutex lock, a call to pthread_mutex_lock() may return the error value [EOWNERDEAD] even if the process in which the owning thread resides has not terminated. In these cases, the mutex is locked by the thread but the state it protects is marked as inconsistent. The application should ensure that the state is made consistent for reuse and when that is complete call pthread_mutex_consistent(). If the application is unable to recover the state, it should unlock the mutex without a prior call to pthread_mutex_consistent(), after which the mutex is marked permanently unusable.