2010-06-03 6 views

ответ

5

Стандартный способ сделать это - создать pidfile где-нибудь, обычно содержащий pid вашей программы.

Вам не нужно вставлять pid, вы можете просто установить на него эксклюзивный замок. Если вы откроете его для чтения/записи и скопируйте его с помощью LOCK_EX | LOCK_NB, он не будет работать, если файл уже заблокирован. Это состояние гонки бесплатно, и блокировка будет автоматически выпущена, если программа выйдет из строя.

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

Если это демон, где-то вроде/var/run лучше.

4

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

Основная логика этого является:

Invariant: 
    File xxxxx will exist if and only if the program is running, and the 
    contents of the file will contain the PID of that program. 

On startup: 
    If file xxxxx exists: 
     If there is a process with the PID contained in the file: 
      Assume there is some instance of the program, and exit 
     Else: 
      Assume that the program terminated abnormally, and 
      overwrite file xxxx with the PID of this program 
    Else: 
     Create file xxxx, and save the current PID to that file. 

On termination (typically registered via atexit): 
    Delete file xxxxx 

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

+0

Не проще ли использовать сокет вместо файла и попытаться связать его с предопределенным портом? И, кстати, почему я не могу использовать блокировку файлов без проверки pid? – jackhab

+0

@ Jack, вы можете сделать это без проверки PID, но тогда вы рискуете предположить, что программа открыта, когда она действительно разбилась и не удалось очистить файл (подумайте о проблеме с Firefox). Кроме того, Rakis поднимает хороший момент, то есть в Linux вы можете проверить, принадлежит ли PID вашей программе, используя данные в '/ proc' ... существуют программные способы сделать это более общее в вариантах UNIX (по крайней мере, вы могли бы вызывать «ps» и анализировать его вывод, хотя я считаю, что могут быть функции, которые вы можете вызвать для получения информации о процессе напрямую). –

+1

, чтобы проверить существование процесса, вызвать kill (pid, 0). Это происходит успешно, когда процесс существует, и в противном случае не выполняется. Остерегайтесь процесса, запущенного на другой машине! – Arkadiy

1

Связанная альтернатива решению Майкла состоит в том, чтобы создать каталог в известном месте (возможно, в/var/run или/tmp) и использовать успех/отказ системного вызова в качестве механизма обеспечения взаимного исключения. Это то же самое взаимное исключение, которое CVS использовал в течение многих лет, поскольку создание каталогов является атомарным для большинства (возможно, всех) товарных ОС. PID-файл по-прежнему полезен в случае, когда процесс создания каталога + PID неожиданно завершается и не удается выполнить очистку. Кроме того, при проверке, действительно ли существующий каталог + PID действителен, я предлагаю явно проверить символическую ссылку /proc/<PID>/exe, чтобы убедиться, что она указывает на ваш исполняемый файл, а не просто на то, что PID не был повторно использован.

-1

Чтобы сделать это, вы можете использовать POSIX named semaphore. Это гораздо безопаснее, чем использование блокировки файлов.

+0

Как это касается программы, которая разбилась без очистки семафора? –

+0

из справочной страницы: POSIX семафоры имеют стойкость ядра: если не удалить sem_unlink(), семафор будет существовать до тех пор, пока система не будет отключена. Проблема, безусловно, будет проблемой здесь. – jackhab

0

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

Вы можете использовать либо некоторые библиотеки (libunique (GTK +), либо QtSingleApplication (Qt)), либо сделать это самостоятельно. В дополнение к pid-файлу, упомянутому ранее, вы можете открыть сокет FIFO или UNIX-домен где-нибудь в домашнем каталоге пользователя. Таким образом, вы можете общаться с запущенным экземпляром, например. поднять окно исполняемого экземпляра или сообщить исполняемому экземпляру, чтобы открыть новый файл/URI/что угодно.

Смежные вопросы