プログラムの実行中にどのようにリアルタイムアップデートを行うことができますか?

プログラムの実行中にどのようにリアルタイムアップデートを行うことができますか?

ThunderbirdやFirefoxなどのキラーアプリがシステムパッケージマネージャを介して実行時にどのように更新されるかを知りたいです。古いコードが更新されたらどうなりますか?実行時に自分で更新されるプログラムa.outを作成するにはどうすればよいですか?

ベストアンサー1

一般的な代替ファイル

まず、ファイルを置き換えるためのいくつかの戦略があります。

  1. 開いている既存の書き込みファイルはゼロ長に切り捨てられ、新しいコンテンツが記録されます。 (あまり一般的なバリエーションは、既存のファイルを開き、古い内容を新しい内容で上書きし、ファイルが短い場合は新しい長さに切り捨てることです)。

    echo 'new content' >somefile
    
  2. 削除する古いファイルを削除し、同じ名前の新しいファイルを作成します。シェル用語で:

    rm somefile
    echo 'new content' >somefile
    
  3. 一時名で新しいファイルを作成し、移動する新しいファイルを既存の名前に変更します。移動すると、古いファイルが削除されます。シェル用語で:

    echo 'new content' >somefile.new
    mv somefile.new somefile
    

私はこれらの戦略の間のすべての違いをリストしているわけではなく、いくつかの重要なことだけを言及します。ポリシー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つの原子操作で行われるため、この戦略には1つの主な利点があります。プロセスがいつでもファイルを開くと、古いコンテンツまたは新しいコンテンツが表示されます。混在したコンテンツを取得したり、ファイルが存在しないリスクはありません。既存の。

実行ファイルの置き換え

実行中の実行可能ファイルを使用してLinuxで戦略1を試みると、エラーが発生します。

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

「テキストファイル」とは、実行可能コードを含むファイルを意味します。未知の歴史的理由から。他の多くのUnixの亜種と同様に、Linuxは実行中のプログラムのコードの上書きを拒否します。一部のUNIXバリアントではこれを許可するため、新しいコードが古いコードを根本的に変更しない限り、競合が発生します。

Linuxでは、ライブラリを動的にロードするコードをオーバーライドできます。これを使用するプログラムがクラッシュする可能性があります。 (sleep起動時に必要なすべてのライブラリコードをロードするため、これを観察することはできません。たとえば、スリープ後に便利なタスクを実行するより複雑なプログラムを試してみてください。perl -e 'sleep 9; print lc $ARGV[0]'

インタプリタがスクリプトを実行している場合、インタプリタはスクリプトファイルを正常に開くため、スクリプトが上書きされるのを防ぐ方法はありません。一部の通訳者は、最初の行の実行を開始する前にスクリプト全体を読み取り、解析し、他の通訳者は必要に応じてスクリプトを読み取ります。バラより実行中にスクリプトを編集するとどうなりますか?そしてLinuxはシェルスクリプトをどのように処理しますか?詳細については。

戦略2と3は実行可能ファイルにも安全です。実行中の実行可能ファイル(および動的にロードされたライブラリ)は、ファイル記述子があるという点で開かれたファイルではありませんが、非常に似た方法で動作します。プログラムがコードを実行している間は、ディレクトリエントリがなくてもファイルはディスクに残ります。

アップグレード申請

ほとんどのパッケージマネージャは、上記の主な利点を持つファイル交換戦略3を使用しています。つまり、どの時点でも開いているファイルの有効なバージョンを取得できるということです。

アプリケーションのアップグレード時に問題が発生する可能性があります。 1つのファイルをアップグレードすることはアトミックですが、アプリケーションが複数のファイル(プログラム、ライブラリ、データなど)で構成されている場合、アプリケーション全体をアップグレードすることはアトミックではありません。次の一連のイベントを考えてみましょう。

  1. アプリケーションインスタンスが起動しました。
  2. アプリケーションがアップグレードされました。
  3. 実行中のインスタンスアプリケーションはデータファイルの1つを開きます。

ステップ3では、実行中の以前のバージョンのアプリケーションインスタンスが新しいバージョンのデータファイルを開きます。これが機能するかどうかは、アプリケーション、ファイルの種類、ファイルの変更の程度によって異なります。

アップグレード後も既存のプログラムが実行され続けていることがわかります。新しいバージョンを実行するには、古いプログラムを終了して新しいバージョンを実行する必要があります。パッケージマネージャは通常、アップグレード時にデーモンをシャットダウンして再起動しますが、エンドユーザーアプリケーションは影響を受けません。

一部のデーモンには、デーモンを終了して新しいインスタンスが再起動されるのを待たずに(サービスが中断される可能性がある)、アップグレードを処理する特別な手順があります。これは、次の状況で必要です。内部に、終了できません。初期化システムは、実行中のインスタンス呼び出しを要求する方法を提供します。execve新しいバージョンに置き換えられます。

おすすめ記事