2010-07-28 3 views
26

Что произойдет, если я перекомпилирую исполняемый файл во время его работы? Означает ли операционная система все содержимое исполняемого файла в памяти при запуске, поэтому никогда не будет читать новый исполняемый файл? Или он прочитает разделы нового исполняемого файла, думая, что он не изменился, что привело к возможно неопределенному поведению?Безопасно ли перекомпилировать исполняемый файл во время его работы?

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

Моя ОС - это Linux, но мне также интересно, что происходит в Windows.

+1

Какой язык и реализация? Для большинства компиляторов Common Lisp нет проблем с заменой исполняемого файла «на лету». Другие системы работают по-разному. –

+0

Это исполняемый файл C++. Я не уверен, как это имеет значение для операционной системы, хотя ... – HighCommander4

+1

Это делает разницу в том, что компиляция и выполнение являются совершенно разными шагами, и поэтому вопрос заключается в том, как ОС обрабатывает исполняемые файлы. –

ответ

28

Поскольку это обычный компилятор, который записывает исполняемый файл, давайте следовать ему в Linux.

Первое, что нужно знать, это то, что имя файла Linux не относится напрямую к файлу, а относится к записи каталога, которая не зависит от имени файла. Файлу на самом деле не нужно иметь имя файла, но если это не так, будет сложно обратиться к нему.

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

Поэтому, если вы перекомпилируете и создаете новый исполняемый файл с таким же именем, вы не будете влиять на текущий процесс. Он будет продолжать использовать старый исполняемый файл. Любой новый процесс, который пытается открыть файл, получит новый. Если у вас есть system("foo"); в цикле, каждый раз, когда он его выполняет, он увидит, что означает имя файла foo.

Windows обрабатывает файлы по-разному. В общем случае, если есть процесс с использованием файла, файл заблокирован и не может быть удален или заменен.

+0

Интересно, что дает мне некоторое представление о том, как Linux обрабатывает файлы. – HighCommander4

+1

[Linux] Это зависит от того, как вы «замените» файл на то, будет ли он работать или нет. Вы не можете открыть исполняемый файл для использования для записи. – camh

+0

Что делать, если на половине выходного файла компоновщика файла .exe я пытаюсь запустить его? Будет ли он пытаться запустить наполовину написанный исполняемый файл? – Thanatos

7

От этого зависит.

Если ОС считывает весь исполняемый файл в память и не ссылается на образ диска, то да, вы можете перекомпилировать его, пока он «используется».

На практике это не всегда происходит. Если ОС держит дескриптор файла открытым (как и Windows) в исполняемом файле, это предотвратит удаление файла и/или перезапись.

С Linux/Unix можно перезаписать файл, который «используется». См. Ответ Дэвида Торнли для подробного объяснения.

0

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

0

зависит от цели. Из того, что я испытал, в Linux вы все еще можете запускать программу, если вы ее удаляете (и она не слишком велика). Но я не думаю, что это определенное поведение.

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

0

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

Я не знаю о Linux.

-1

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

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

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

Не уверен относительно Linux, но IIRC он выполняет обмен данными таким же образом.

5

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

Таким образом, вы могли бы

  • движение старого ехе в временный каталог на том же диске
  • график его для удаления при следующей перезагрузке: MoveFileEx (имя, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
  • переместите новый exe на свое место.

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

+3

Интересная информация, которая может быть использована для демонстрации того, насколько плохие варианты дизайна могут привести к странным обходным решениям. Разбирая информацию о файле, filename и inode, нет необходимости в таких сложных командах. Кроме того, нет необходимости перезагружаться. Обновление может произойти «на лету». – Saurabh

4

В Linux, при необходимости, исполняемые файлы запрашиваются в памяти. Исполняемый файл на диске становится хранилищем для приложения. Это означает, что вы не можете изменить исполняемый файл на диске или повлиять на запущенное приложение. Если вы попытаетесь выполнить open(2) исполняемый файл для использования, вы получите ошибку ETXTBSY (текстовый файл занят) (проверьте справочную страницу для open(2)).

Как многие другие говорили, вы можете удалить файл из файловой системы (unlink(2)), и ядро ​​будет поддерживать ссылку на него, а не удалять его с диска, пока не будет больше ссылок (когда процесс завершится, он будет отпустите ссылку на файл). Это означает, что вы можете эффективно «перезаписать» исполняемый файл, удалив его, а затем создав новый файл с тем же именем, что и старый файл.

Итак, дело сводится к тому, как компилятор создает исполняемый файл при «перезаписи» существующего файла. Если он просто открывает файл для записи и усекает его (O_WRONLY|O_CREAT|O_TRUNC), он сбой не будет с ошибкой ETXTBSY. Если он сначала удаляет существующий выходной файл и создает новый, он будет работать без ошибок.

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