Надежный мьютекс не работает с общей памятью - PullRequest
1 голос
/ 29 апреля 2020

Я использую реализацию разделяемого мьютекса памяти, найденную здесь: https://gist.github.com/yamnikov-oleg/abf61cf96b4867cbf72d

Меня беспокоило поведение владельца мьютекса, если процесс, который имеет захват замка, вылетает. Из моего тестирования кажется, что другие процессы не смогут получить блокировку. Я нашел концепцию надежных мьютексов при поиске и изменил код, изменив эту часть:

  // 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;
    }
  }

Код, который использует эти файлы:

  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;
    }
  }

Для тестирования я запустите два экземпляра программы и проследите, как между ними передается владение блокировкой. Когда я == 5, программа прервется, и право собственности должно быть передано для следующего вызова блокировки, исходя из того, что я прочитал о надежных мьютексах.

Но, похоже, ничего не изменилось, и поведение так же, как и прежде, я что-то изменил. Есть идеи, как поступить? Заранее спасибо.

Редактировать:

Использование pthread_mutex_trylock дает правильное поведение программы. Кажется, что файл «my-mutex», созданный в /dev/shm, содержал экземпляр мьютекса, который я использовал в предыдущих попытках, который не включал надежную настройку, которую я позже изменил. Удаление и запуск с вышеупомянутой функцией приводит к возврату OWNERDEAD, и процесс может заблокировать мьютекс.

1 Ответ

3 голосов
/ 29 апреля 2020

Документация гласит :

Объект мьютекса, на который ссылается мьютекс, должен быть заблокирован вызовом pthread_mutex_lock(), который возвращает ноль или [EOWNERDEAD].

Вы неправильно обрабатываете код возврата [OWNERDEAD], поэтому вам не хватает повторной блокировки мьютекса.

Подробнее о том, как это следует обрабатывать:

Если мьютекс является надежным мьютексом, и поток-владелец завершился, удерживая блокировку мьютекса, вызов pthread_mutex_lock() может вернуть значение ошибки [EOWNERDEAD], даже если процесс, в котором находится поток-владелец, не завершился. В этих случаях мьютекс блокируется потоком, но состояние, которое он защищает, помечается как несогласованное. Приложение должно убедиться, что состояние сделано согласованным для повторного использования, и когда это будет завершено, вызовите pthread_mutex_consistent(). Если приложение не может восстановить состояние, оно должно разблокировать мьютекс без предварительного вызова pthread_mutex_consistent(), после чего мьютекс помечается как неиспользуемый.

...