Подтвердить что ты не робот

Как восстановить семафор, когда процесс, который уменьшил его до нуля, падает?

У меня есть несколько приложений, скомпилированных с g++, работающих в Ubuntu. Я использую названные семафоры для координации между различными процессами.

Все работает отлично, за исключением следующей ситуации: Если один из процессов вызывает sem_wait() или sem_timedwait(), чтобы уменьшить семафор, а затем сбой или был убит -9, прежде чем он получит возможность вызвать sem_post(), то из в этот момент названный семафор "неприменим".

Под "непригодным", я имею в виду, что счет семафора теперь равен нулю, и процесс, который должен был увеличить его до 1, умер или был убит.

Я не могу найти API sem_*(), который мог бы рассказать мне, что последний из них уменьшился.

Я где-то пропускаю API?

Вот как я открываю именованный семафор:

sem_t *sem = sem_open( "/testing",
    O_CREAT     |   // create the semaphore if it does not already exist
    O_CLOEXEC   ,   // close on execute
    S_IRWXU     |   // permissions:  user
    S_IRWXG     |   // permissions:  group
    S_IRWXO     ,   // permissions:  other
    1           );  // initial value of the semaphore

Вот как я его уменьшаю:

struct timespec timeout = { 0, 0 };
clock_gettime( CLOCK_REALTIME, &timeout );
timeout.tv_sec += 5;

if ( sem_timedwait( sem, &timeout ) )
{
    throw "timeout while waiting for semaphore";
}
4b9b3361

Ответ 1

Оказывается, нет надежного восстановления семафора. Конечно, любой может post_sem() присвоить названному семафору, чтобы счет снова увеличился за ноль, но как сказать, когда такое восстановление необходимо? Предоставленный API слишком ограничен и никоим образом не указывает, когда это произошло.

Остерегайтесь доступных инструментов ipc - общие инструменты ipcmk, ipcrm и ipcs предназначены только для устаревших семафоров SysV. Они специально не работают с новыми семафорами POSIX.

Но похоже, что есть другие вещи, которые можно использовать для блокировки вещей, которые операционная система автоматически освобождает, когда приложение умирает таким образом, что его невозможно поймать в обработчике сигналов. Два примера: прослушивающий сокет, привязанный к определенному порту, или блокировка для определенного файла.

Я решил, что блокировка файла - это необходимое мне решение. Поэтому вместо вызовов sem_wait() и sem_post() я использую:

lockf( fd, F_LOCK, 0 )

и

lockf( fd, F_ULOCK, 0 )

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

Спасибо за помощь, ребята.

Ответ 2

Используйте файл блокировки вместо семафора, как и решение @Stéphane, но без вызовов flock(). Вы можете просто открыть файл с помощью эксклюзивной блокировки:

//call to open() will block until it can obtain an exclusive lock on the file.
errno = 0;
int fd = open("/tmp/.lockfile", 
    O_CREAT | //create the file if it not present.
    O_WRONLY | //only need write access for the internal locking semantics.
    O_EXLOCK, //use an exclusive lock when opening the file.
    S_IRUSR | S_IWUSR); //permissions on the file, 600 here.

if (fd == -1) {
    perror("open() failed");
    exit(EXIT_FAILURE);
}

printf("Entered critical section.\n);
//Do "critical" stuff here.

//exit the critical section
errno = 0;
if (close(fd) == -1) {
    perror("close() failed");
    exit(EXIT_FAILURE);
}

printf("Exited critical section.\n");

Ответ 3

Это типичная проблема при управлении семафорами. Некоторые программы используют один процесс для управления инициализацией/удалением семафора. Обычно этот процесс делает именно это и ничего больше. Ваши другие приложения могут ждать, пока семафор не будет доступен. Я видел это с API типа SYSV, но не с POSIX. Подобно тому, что упоминалось в " Duck", используя флаг SEM_UNDO в вашем вызове semop().


Но, с информацией, которую вы предоставили, я предлагаю вам не использовать семафоры. Особенно, если ваш процесс находится в опасности быть убитым или сбой. Попытайтесь использовать что-то, что ОС будет автоматически автоматизировать для вас.

Ответ 4

Вы можете найти его из оболочки с помощью lsof. Тогда, возможно, вы можете удалить его?

Обновление

А да... man -k semaphore на помощь.

Кажется, вы можете использовать ipcrm, чтобы избавиться от семафора. Кажется, вы не первый с этой проблемой.

Ответ 5

Вам нужно будет дважды проверить, но я верю, что sem_post можно вызвать из обработчика сигнала. Если вы можете поймать некоторые ситуации, которые приводят к снижению процесса, это может помочь.

В отличие от мьютекса любой процесс или поток (с разрешениями) могут отправлять сообщения в семафор. Вы можете написать простую утилиту для reset it. Предположительно, вы знаете, когда ваша система зашла в тупик. Вы можете снести его и запустить служебную программу.

Также семафон обычно указан в /dev/shm, и вы можете его удалить.

Семафоры SysV более подходят для этого сценария. Вы можете указать SEM_UNDO, в котором система вернет изменения в семафор, созданный процессом, если он умрет. Они также могут сообщить вам последний идентификатор процесса, чтобы изменить семафор.

Ответ 6

Если процесс был KILLED, тогда не будет никакого прямого способа определить, что он ушел.

Вы можете использовать некоторую периодическую проверку целостности всех семафоров, которые у вас есть, - используйте semctl (cmd = GETPID), чтобы найти PID для последнего процесса, который касался каждого семафора в описываемом вами состоянии, а затем проверить, все ли еще этот процесс. Если нет, выполните очистку.

Ответ 7

Просто выполните sem_unlink() сразу после sem_open(). Linux удалит после того, как все процессы закроют ресурс, который включает внутренние закрытия.