Что определяет, может ли исполняемый файл запускаться в разных независимых процессах одновременно?

Что определяет, может ли исполняемый файл запускаться в разных независимых процессах одновременно?

Я отправилвопросо том, как запустить исполняемый файл (просмотрщик PDF) под wine независимо в нескольких процессах (независимость означает отсутствие связи между ними, это не параллельные вычисления). Я слышал, что редактор PDF (расширенная версия просмотрщика) какой-то компании не может этого сделать.

Вопросы

  • Так вот мне интересно, что делает исполняемый файл способным или неспособным работать независимо в нескольких процессах?
  • Реализовано ли это самой программой, какими-то библиотеками?
  • Разве ОС не может этого добиться?

решение1

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

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

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

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

Многие простые самодельные приложения проверяют, запущена ли уже другая версия самого себя, просто запрашивая ps. Это можно обойти разными способами. Проблема с промышленным программным обеспечением заключается в том, что пользователь почти никогда не знает, как конкретное приложение решает, используется ли оно уже или нет. Даже в Unix, где вы можете проверить все открытые файлы, с которыми взаимодействует исполняемый файл, нет гарантии, что вы сможете выяснить, какой из них (если какой-либо из них) отвечает за регистрацию факта запуска приложения.

решение2

Процесс — это экземпляр программы. Программа может быть экземпляром несколько раз, то есть может быть создано несколько процессов с загруженным одним и тем же исполняемым кодом.Я хотел бы процитировать строчку изПонимание ядра LinuxДэниел П. Бове и Марко Чезати:

Важно отличать программы от процессов; несколько процессов могут выполнять одну и ту же программу.одновременно, в то время как один и тот же процесс может выполнять несколько программпоследовательно.

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

Еще один момент кажется мне важным, когда речь идет о Unix-подобных системах (та же книга):

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

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

Однако каждый процесс знает одно: система работает под управлением ядра, и службы ядра находятся в распоряжении процесса на все время, которое он будет проводить, работая на ЦП. Благодаря этому процесс можетзапросядро о других процессах, запущенных как экземпляры того же исполняемого файла. Первое решение, которое приходит мне в голову, — прочитать /procвиртуальную файловую систему. Эта файловая система действует как интерфейс между пользователем/приложением и ядром (поскольку эти файлы представляют структуры и данные ядра). В этой файловой системе каждому процессу назначается каталог (названный его PID), и внутри этого каталога вы найдете ссылку с именем exe. Например, вот bashкаталог моего процесса, PID 22343:

lrwxrwxrwx /proc/22343/exe -> /bin/bash*

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

Однако, поскольку все системы Unix реализуются /procпо-разному, разработчики стремятся использовать более переносимое решение, которое опирается на то, что понимают практически все системы Unix: обычные файлы. Вот для чего .pidобычно здесь и существуют файлы.

Чаще всего вы найдете эти файлы в формате /run. Например:

-rw-r--r-- /run/acpid.pid
-rw-r--r-- /run/atd.pid
-rw-r--r-- /run/crond.pid

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

Теперь, поскольку все процессы одной и той же программы используют один и тот же код выполнения, они используют свои константы (по крайней мере, свои значения). По этой причине, если каждый экземпляр знает, где искать PID-файл, программирование одноэкземплярной программы становится довольно простым:

if (the pid file exists) then
    send a signal to the running process or just bring it on the foreground
    exit since the work is going to be handled by the already-running process
else
    actually start the program, the first instance
endif

Использование сигналов в первом случае — это поведение, которое я видел чаще всего, однако, если ваше приложение использует более сложный IPC (сокеты, очереди сообщений и т. д.), вы можете использовать его, чтобы сообщить ему, что пользователь запросил что-то, что ему нужно сделать.

Связанный контент