Как заблокировать запуск двух экземпляров одной и той же программы?

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

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

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

Кажется, что это работает очень хорошо – даже после неожиданного закрытия, вероятность того, что (теперь устаревший) ID процесса будет связана с какой-то другой программой, кажется довольно низкой.

Но он все еще не чувствует себя хорошо (есть шанс заблокировать какой-то несвязанный процесс), и работа с идентификаторами процессов, похоже, выходит за frameworks стандартного C ++ и, вероятно, также не очень переносима.

Итак, есть ли другой (более чистый и безопасный) способ сделать это? В идеале это будет работать со стандартом ISO 98 C ++ и Windows и * nix.
Если это невозможно, независимо от платформы, Linux / Unix является для меня приоритетом.

Существует несколько методов, позволяющих выполнить только один экземпляр вашего приложения:

Способ 1. Глобальный объект или память синхронизации

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

Например, в windowsх вы можете:

#define APPLICATION_INSTANCE_MUTEX_NAME "{BA49C45E-B29A-4359-A07C-51B65B5571AD}" //Make sure at most one instance of the tool is running HANDLE hMutexOneInstance(::CreateMutex( NULL, TRUE, APPLICATION_INSTANCE_MUTEX_NAME)); bool bAlreadyRunning((::GetLastError() == ERROR_ALREADY_EXISTS)); if (hMutexOneInstance == NULL || bAlreadyRunning) { if(hMutexOneInstance) { ::ReleaseMutex(hMutexOneInstance); ::CloseHandle(hMutexOneInstance); } throw std::exception("The application is already running"); } 

Способ 2. Блокировка файла, вторая программа не может открыть файл, поэтому он открыт

Вы также можете открыть файл исключительно, заблокировав его при открытии приложения. Если файл уже открыт, и ваше приложение не может получить дескриптор файла, значит, программа уже запущена. В Windows вы просто не укажете флаги обмена FILE_SHARE_WRITE в файле, который вы открываете с CreateFile API CreateFile . На linux вы будете использовать flock .

Способ 3: Поиск имени процесса:

Вы можете перечислять активные процессы и искать их с именем процесса.

Ваш метод записи процесса pid в файл является общим, который используется во многих различных установленных приложениях. Фактически, если вы посмотрите в свой каталог /var/run прямо сейчас, я уверен, вы найдете несколько файлов *.pid .

Как вы говорите, она не на 100% надежна, потому что есть вероятность того, что pids запутаются. Я слышал о программах, использующих flock() чтобы заблокировать файл приложения, который будет автоматически разблокирован ОС при выходе из процесса, но этот метод более специфичен для платформы и менее прозрачен.

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

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

Очень un-unix запрещает запуск нескольких экземпляров программы.

Если программа является, скажем, сетевым деmonoм, не нужно активно запрещать несколько экземпляров – только первый экземпляр прослушивает сокет, поэтому последующие экземпляры автоматически запускаются. Если это, скажем, РСУБД, нет необходимости активно запрещать несколько экземпляров – только первый экземпляр открывает и блокирует файлы. и т.п.

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

«Правильный» способ сделать это, вероятно, использовать общую память: http://www.cs.cf.ac.uk/Dave/C/node27.html

Если вы хотите что-то, что является стандартом болота, то использование файла как «блокировки» – это в значительной степени путь. У этого есть недостаток, о котором вы говорили (если ваше приложение не очищается, перезапуск может быть проблемой).

Этот метод используется довольно многими приложениями, но единственное, что я могу вспомнить с моей головы, – это VMware. И да, есть моменты, когда вам нужно войти и удалить «* .lck», когда все вклинится.

Использование глобального мьютекса или другого системного объекта, как упомянуто Брайаном Бонди, – лучший способ пойти, но они специфичны для платформы (если вы не используете какую-либо другую библиотеку для абстрагирования специфики платформы).

У меня нет хорошего решения, но две мысли:

  1. Вы можете добавить возможность ping для запроса другого процесса и убедиться, что это не несвязанный процесс. Firefox делает что-то подобное в Linux и не запускает новый экземпляр, если он уже запущен.

  2. Если вы используете обработчик сигнала, вы можете убедиться, что файл pid удален на всех, кроме kill -9

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

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

Очевидно, что это зависит от Windows, но одна и та же концепция довольно проста в любой системе * NIX даже без конкретных библиотек, просто открыв команду оболочки ps -ef или изменив ее и ищет ваше приложение.

  '************************************************************************* ' Sub: CheckForProcess() ' Author: Ron Savage ' Date: 10/31/2007 ' ' This routine checks for a running process of this app with the same ' command line parameters. '************************************************************************* Private Function CheckForProcess(ByVal processText As String) As Boolean Dim isRunning As Boolean = False Dim search As New ManagementObjectSearcher("SELECT * FROM Win32_process") Dim info As ManagementObject Dim procName As String = "" Dim procId As String = "" Dim procCommandLine As String = "" For Each info In search.Get() If (IsNothing(info.Properties("Name").Value)) Then procName = "NULL" Else procName = Split(info.Properties("Name").Value.ToString, ".")(0) If (IsNothing(info.Properties("ProcessId").Value)) Then procId = "NULL" Else procId = info.Properties("ProcessId").Value.ToString If (IsNothing(info.Properties("CommandLine").Value)) Then procCommandLine = "NULL" Else procCommandLine = info.Properties("CommandLine").Value.ToString If (Not procId.Equals(Me.processId) And procName.Equals(processName) And procCommandLine.Contains(processText)) Then isRunning = True End If Next Return (isRunning) End Function 

Я нашел кросс-платформенный способ сделать это, используя boost/interprocess/sync/named_mutex . См. Этот ответ https://stackoverflow.com/a/42882353/4806882

  • Разница в арифметике с плавающей запятой между x86 и x64
  • Что такое имя массива в c?
  • Почему происходит отключение функции не-void без возврата значения, не приводящего к ошибке компилятора?
  • Включить Entity Framework 6 для MySql (C #) в WinForms Microsoft Visual Studio 2013
  • Виртуальное наследование c ++
  • Несколько проблем «не удалось решить» с помощью Eclipse с minGW
  • char * vs std :: string в c ++
  • Статический и глобальный
  • Почему polymorphism не работает без указателей / ссылок?
  • Linq упорядочивает, группирует и упорядочивает по каждой группе?
  • Изучение C ++: polymorphism и нарезка
  • Давайте будем гением компьютера.