Приложение только для одного экземпляра в C и Linux

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

sem_t one_instance_only=sem_open(UNIQUE_NAME,O_CREAT | O_EXCL,...);
if(SEM_FAILED==one_instance_only)
{
    if(E_EXIST==errno)
    {
    // application already running
    exit(1);
    }
}
sem_close(...);
//without the call to sem_unlink() the semaphore still lingering even if app not 
// running
sem_unlink(...);     

Я попробовал это, и он работает, но я просто хочу убедиться, что я делаю это правильно, и где-то нет места.

Ответ 1

На самом деле вы не используете функциональные возможности семафора. Вы можете иметь тот же эффект с обычным файлом, использовать open с O_CREAT | O_EXCL и отсоединяться при выходе.
Вы можете использовать один и тот же файл для записи своего ПИД-кода в нем ( "pidfile" ), а затем, если open не прочитает PID и использует его, чтобы проверить, принадлежит ли он другому экземпляру вашей программы, или просто там, потому что он не был отключен из-за к сбою.

Ответ 2

Ловушка заключается в том, что логика не обеспечивает уверенность в том, что экземпляр приложения будет выполнен. Что, если существующее приложение уже решило выйти и выполняет путь выхода, но еще не вызвало sem_close? Новый экземпляр считает "я ненужен", потому что семафор все еще существует и выходит. Конечным результатом является то, что ничего не работает.

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

Одним из способов решения проблемы будет использование некоторого механизма IPC. Например, новый экземпляр сервера может связаться с существующим экземпляром и поместить запрос "пожалуйста, продолжайте работать, если это возможно". Если с сервером невозможно связаться или ответ на запрос отрицательный, он может взять на себя как новый экземпляр.

Вам также понадобится это, если есть требование передать запрос существующему экземпляру. Предположим, что у программы есть аргументы командной строки и необходимо предпринять некоторые действия. Или, вот знакомый пример: подумайте о браузере: пользователь хочет, чтобы ОС открывала URL-адрес, и должен использоваться существующий экземпляр браузера. Если новый браузер не будет запущен, этот URL-адрес должен быть передан в существующий экземпляр в качестве запроса. Недостаточно просто заметить, что существует существующий экземпляр и уходит, потому что запрос на запуск - это событие, которое было сделано по какой-то причине: кто-то или что-то хочет, чтобы программа что-то делала. Логика, которая у вас есть, подходит только для процесса типа демона, который считывает конфигурацию, а затем прослушивает запросы и запуск которой не является ничем для запуска.

Ответ 3

Я только что написал и протестировал.

#define PID_FILE "/tmp/pidfile"
static void create_pidfile(void) {
    int fd = open(PID_FILE, O_RDWR | O_CREAT | O_EXCL, 0);

    close(fd);
}

int main(void) {
    int fd = open(PID_FILE, O_RDONLY);
    if (fd > 0) {
        close(fd);
        return 0;
    }

    // make sure only one instance is running
    create_pidfile();
}