Как возможно сделать живое обновление, в то время как программа работает?

Если cat не печатает ошибок, это было, успешно выполняются. Если Вы не видите данных в All_Enc_Coords.txt, проверьте, пуст ли local_enc* также.

Вы не должны контролировать записи файла, если кошка выходит, запись закончена; Если это работает в другом сценарии, используйте inotify для прислушиваний к сигналу WRITE_CLOSE.

15
20.06.2014, 11:20
3 ответа

Замена файлов в целом

Во-первых, существует несколько стратегий замены файла:

  1. Открыть существующий файл для записи, усечь его до 0 длины и записать новое содержимое. (Менее распространенный вариант - открыть существующий файл, перезаписать старое содержимое новым содержимым, усечь файл до новой длины, если он короче). В терминах оболочки:

    echo 'new content' >somefile
    
  2. Удалите старый файл и создайте новый файл с тем же именем. В терминах оболочки:

    rm какой-то файл
    echo 'new content' >somefile
    
  3. Запишите новый файл под временным именем, затем переместите новый файл на существующее имя. При этом удаляется старый файл. В терминах оболочки:

    echo 'new content' >somefile.new
    мой кое-что новый кое-что
    

Я не буду перечислять все различия между стратегиями, я просто упомяну некоторые, которые здесь важны. В категории 1, если какой-либо процесс в настоящее время использует файл, он видит новое содержимое по мере его обновления. Это может вызвать некоторую путаницу, если процесс ожидает, что содержимое файла останется прежним. Обратите внимание, что речь идет только о процессах, у которых открыт файл (как видно в lsof или в /proc/PID/fd/; интерактивные приложения, у которых открыт документ (например обычно не держат файл открытым, загружают содержимое файла во время операции "открыть документ" и заменяют файл (используя одну из вышеперечисленных стратегий) во время операции "сохранить документ".

При использовании стратегий 2 и 3, если в каком-либо процессе открыт файл somefile, старый файл остается открытым во время обновления содержимого. В случае стратегии 2 этап удаления файла фактически только удаляет запись файла в каталоге. Сам файл удаляется только тогда, когда у него нет записи в каталоге, ведущей к нему (в типичных файловых системах Unix для одного и того же файла может быть более одной записи в каталоге). и ни один процесс не открыт. Вот способ наблюдать это - файл удаляется только когда процесс sleep убит (rm только удаляет свой вход каталога).

echo 'old content' >somefile
sleep 9999999 <somefile &
df .
rm somefile
df .
cat /proc/$!/fd/0
kill $!
df .

С стратегией 3, шаг перемещения нового файла к существующему имени удаляет вход каталога, ведущий к старому содержимому и создает вход каталога, ведущий к новому содержимому. Это делается за одну атомарную операцию, поэтому у этой стратегии есть основное преимущество: если процесс откроет файл в любой момент времени, он увидит либо старое содержимое, либо новое - нет риска получить смешанное содержимое, либо файл несуществующий.

Замена исполняемых файлов

Если вы попробуете стратегию 1 с работающим исполняемым файлом под Linux, вы получите ошибку.

cp /bin/sleep .
./sleep 999999 &
echo oops >|sleep
bash: sleep: Text file busy

Текстовый файл" означает файл, содержащий исполняемый код по непонятным историческим причинам. Linux, как и многие другие unix-варианты, отказывается перезаписывать код запущенной программы; несколько unix-вариантов позволяют это, что приводит к аварийному завершению работы, если только новый код не был очень хорошо продуманной модификацией старого кода.

В Linux можно перезаписать код динамически подгружаемой библиотеки. Скорее всего, это приведет к аварийному завершению работы программы, которая его использует. (Вы можете не заметить этого с помощью sleep, так как она загружает весь код библиотеки, который ей нужен, когда она запускается. Попробуйте более сложную программу, которая делает что-то полезное после сна, например perl -e 'sleep 9; print lc $ARGV[0]'.)

Если интерпретатор выполняет скрипт, то файл скрипта открывается интерпретатором обычным способом, так что никакой защиты от перезаписи скрипта нет. Некоторые интерпретаторы читают и анализируют весь скрипт перед началом выполнения первой строки, другие читают скрипт по мере необходимости. Смотрите Что произойдет, если вы отредактируете скрипт во время выполнения? и Как Linux работает со скриптами оболочки? подробнее.

Стратегии 2 и 3 безопасны и для исполняемых файлов: хотя исполняемые файлы (и динамически загружаемые библиотеки) не являются открытыми файлами в смысле наличия дескриптора файла, они ведут себя очень похожим образом. Пока какая-либо программа выполняет код, файл остается на диске даже без записи в каталоге.

Обновление приложения

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

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

  1. Запускается экземпляр приложения.
  2. Обновляется приложение.
  3. Исполняющийся экземпляр приложения открывает один из своих файлов данных.

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

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

У некоторых демонов есть специальные процедуры для обработки обновлений без необходимости убивать демона и ждать перезапуска нового экземпляра (что приводит к нарушению работы сервиса). Это необходимо в случае init, который не может быть убит; init-системы предоставляют возможность запросить, чтобы запущенный экземпляр вызвал execve для замены себя на новую версию.

.
21
27.01.2020, 19:49

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

Пояснение: на Linux-системах файл является просто инодом, на который может быть несколько ссылок. Например, /bin/bash, который вы видите, это просто ссылка на inode 3932163 в моей системе. Вы можете найти, какой из inode что-то делает по ссылке, отправив ls --inode /path на ссылку. Файл (inode) удаляется только в том случае, если на него есть нулевая ссылка и он не используется ни одной программой. Когда менеджер пакетов обновляется, например, /usr/bin/firefox, он сначала удаляет ссылки (удаляет жесткую ссылку /usr/bin/firefox), а затем создает новый файл с именем /usr/bin/firefox, который является жесткой ссылкой на другой вход (тот, который содержит новую версию firefox). Старый код теперь помечен как свободный и может быть использован повторно для хранения новых данных, но остается на диске (коды создаются только при сборке файловой системы и никогда не удаляются). При следующем запуске firefox будет использоваться новый.

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

3
27.01.2020, 19:49

Интересно, как такие киллерские приложения, как Thunderbird или Firefox, могут обновляться через менеджер пакетов системы во время их работы?. Ну, могу сказать, что это не очень хорошо работает... У меня был Firefox перерыв на меня довольно ужасно, если я оставил его открытым, пока пакет обновления был запущен. Я должен был убить его силой иногда и перезапустить его, потому что он был настолько сломан, что я даже не мог закрыть его должным образом.

Что происходит со старым кодом, пока они обновляются? Обычно под Linux программа загружается в память, поэтому исполняемый файл на диске не нужен и не используется во время работы программы. На самом деле вы даже можете удалить исполняемый файл, и программе все равно... Однако, некоторым программам может понадобиться исполняемый файл, и некоторые операционные системы (например, Windows) заблокируют исполняемый файл, предотвращая его удаление или даже переименование/перемещение во время работы программы. Firefox ломается, потому что на самом деле он довольно сложный и использует кучу файлов данных, которые говорят ему, как построить свой GUI (пользовательский интерфейс). Во время обновления пакета эти файлы перезаписываются (обновляются), поэтому, когда старый исполняемый файл Firefox (в памяти) пытается использовать новые GUI-файлы, могут происходить странные вещи...

Что мне нужно делать, когда я хочу написать программу a.out, которая сама себя обновляет во время работы?. На ваш вопрос уже есть много ответов. Зацените: https://stackoverflow.com/questions/232347/how-should-i-implement-an-auto-updater Кстати, вопросы по программированию лучше задавать на StackOverflow.

0
27.01.2020, 19:49

Теги

Похожие вопросы