У меня есть несколько приложений, скомпилированных с g ++, работающий в Ubuntu. Я использую названные семафоры для координирования между различными процессами.
Все хорошо работает кроме следующей ситуации: Если один из вызовов процессов sem_wait()
или sem_timedwait()
постепенно уменьшать семафор и затем отказывает или уничтожается-9, прежде чем это получит шанс звонить sem_post()
, тогда с того момента на, именованный семафор "неприменим".
"Неприменимым", что я имею в виду, семафорное количество, теперь нуль, и процесс, который должен был увеличить его назад к 1, умер или был уничтожен.
Я не могу найти a sem_*()
API, который мог бы сказать мне процесс, который в последний раз постепенно уменьшил его, отказал.
Я пропускаю 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";
}
Оказывается, надежного восстановления семафора нет. Конечно, любой может post_sem()
к названному семафору, чтобы снова увеличить счетчик до нуля, но как сказать, когда такое восстановление необходимо? Предоставляемый API слишком ограничен и никак не указывает, когда это произошло.
Остерегайтесь также инструментов ipc -- общие инструменты ipcmk
, ipcrm
и ipcs
предназначены только для устаревших семафоров SysV. В частности, они не работают с новыми семафорами POSIX.
Но похоже, что есть и другие вещи, которые могут быть использованы для блокировки, которые операционная система автоматически освобождает, когда приложение умирает таким образом, что не может быть поймано обработчиком сигнала. Два примера: прослушивающий сокет, привязанный к определённому порту, или блокировка на определённом файле.
Я решил, что блокировка файла - это то решение, которое мне нужно. Поэтому вместо вызова sem_wait()
и sem_post()
я использую:
lockf( fd, F_LOCK, 0 )
и
lockf( fd, F_ULOCK, 0 )
Когда приложение выходит любым способом, файл автоматически закрывается, что также освобождает блокировку файла. Другие клиентские приложения, ожидающие "семафор", могут продолжать работу, как и ожидалось.
Спасибо за помощь, ребята.
Вы должны быть в состоянии найти его из оболочки, используя LSOF
. Тогда, возможно, вы можете удалить его?
Обновление
Ах да ... Man -k Semaphore
к спасению.
Кажется, что вы можете использовать IPCRM
, чтобы избавиться от семафора. Кажется, вы не первые с этой проблемой.
Если процесс был убит, то не будет никакого прямого способа определить, что он ушел.
Вы можете управлять какой-то проверкой периодической целостности во всех семафорах, которые у вас есть - используйте SEMCTL (cmd = getpid), чтобы найти PID для последнего процесса, который касался каждого семафора в состоянии, который вы описываете, Затем проверьте, остается ли этот процесс все еще вокруг. Если нет, выполните очистку.
Это типичная проблема при управлении семафорами. Некоторые программы используют один процесс для управления инициализацией / удалением семафора. Обычно этот процесс делает только это и больше ничего. Ваши другие приложения могут дождаться, пока не будет доступен семафор. Я видел это сделано с помощью API типа SYSV, но не с POSIX. Подобно тому, что « утка упоминается, используя флаг Sem_undo в вашем SEMOP ().
Но с информацией, которую вы предоставили, я бы предположил, чтобы вы не использовали семафоры. Особенно, если ваш процесс в опасности быть убитым или разбитым. Попробуйте использовать то, что ОС будет автоматически очистить для вас.
Вам нужно будет дважды проверить, но считаю, что SEM_POST может быть вызван из обработчика сигнала. Если вы можете поймать некоторые ситуации, которые способствуют процессу, это может помочь.
В отличие от Mutex любой процесс или нить (с разрешениями), может опубликовать в семафор. Вы можете написать простую утилиту для сброса его. Предположительно, вы знаете, когда ваша система не заблокирована. Вы можете принести его и запустить коммунальную программу.
Также семафон обычно перечислен под / dev / shm, и вы можете удалить его.
SYSV SEMAPHORS более любые для этого сценария. Вы можете указать SEM_undo, в котором система откажется от изменения в семафоре, сделанном процессом, если он умирает. У них также есть возможность сказать вам последний идентификатор процесса, чтобы изменить семафор.