$ g++ program.cpp
$ ./a.out &
(program.cppが変更されます。)
$ g++ program.cpp
実行可能ファイルが上書きされた場合でも、実行中のプロセスで正確な結果を生成するにはどうすればよいですか?
$ g++ program.cpp
$ ./a.out &
(program.cppが変更されます。)
$ g++ program.cpp
実行可能ファイルが上書きされた場合でも、実行中のプロセスで正確な結果を生成するにはどうすればよいですか?
古いファイルがまだ存在するためです。ディレクトリ エントリは新しいファイルを指しますが、古いファイルは開いている限り存在します。閉鎖されたら、最終的に削除されます。つまり、Unix 上です。Windows では、ファイルが開いていて上書きできないため、これを実行できない可能性があります。
これは、新しい実行可能ファイルを作成する方法ld
(によって呼び出される) に大きく依存します。g++
(ファイルが存在しない場合に適切なフラグを作成して)実行するだけopen
の場合、実行中のプロセスに何が起こるかはページングに依存しますが、クラッシュする可能性は十分にあります。最初にunlink
実行すると、新しいファイルを作成する前に、実行中のプロセスは引き続き古いイメージを使用し、プロセスが終了したときにのみ解放されます。
従来、オリジナルの Unix リンカは最初の戦略を使用していました。これには、既存の実行可能ファイルへのアクセス権を維持できるという利点があります。ただし、これは仮想メモリの時代より前のことで、実行可能ファイルが の呼び出しで一度にロードされ、exec
その後ファイルに何が起こったかは関係ありませんでした。今日、リンカーを作成する場合、2 番目を使用しますが、最初に元のファイルのモードを読み取り、同じモードで新しいファイルを作成します。
ls -il
実行可能ファイルを作成し、モードを変更して実行し、再コンパイルして、もう一度実行することで、どの戦略が使用されているかを簡単に確認できますls -il
。inode 番号が変更された場合、リンカはunlink
出力を開く前に実行しています。また、モードが変更された場合 (環境内のデフォルトに戻った場合)、リンカーは、
unlink
.
Linux の g++ の場合、inode 番号とモードの両方が変更されます。(モードがバグを変更するという事実を考慮します。) 一方、ld
Solaris の下の IIRC はファイルを削除しませんでした。上記のテストを行ったことを思い出せませんが、彼らが使用していた DLL の 1 つを再コンパイルしました。
最後に、FWIW、ファイルを削除してもアプリケーションがクラッシュしない理由: Unix のファイル (inode で表される) は参照カウントされ、参照カウントが 0 になると自動的に削除されます。(非常によく似ていshared_ptr
ます。) 参照カウントがあります。ファイルを指す各ディレクトリ エントリ (各ハード リンク)、およびファイルを参照する各オープン ファイル記述子。Unix でのファイルの「削除」は、実際にはファイルに影響を与えるのではなく、そのファイルを指しているディレクトリ エントリを削除するだけです (これにより、使用回数が減少し、ファイルが削除される可能性があります)。ロードされた実行可能ファイルには、その実行可能ファイルと.so
ロードされたすべての のオープン ファイル記述子が含まれます。これは、ファイルへの参照としてカウントされるため、それを指す最後のディレクトリ エントリを削除しても、参照カウントは 0 より大きいままになります。
編集:リンクを解除するとハードリンクも壊れることを追加するかもしれません(古いバージョンを指し続けます)。誰もがソフト リンク (ファイル名への参照であり、ファイル自体への参照ではない) のみを使用するため、これはおそらく今日の問題ではありませんが、ソフト リンクが存在する前の初期の頃を思い出すことができます。リンクを壊さないでください: 私が取り組んだエディタでは、出力をまったく新しいファイルに書き込んでから、それを元のファイルに移動する (inode 数が 1 の場合) か、それをコピーしました (inode 数が 1 より大きい場合)。 ; つまり、私たちが知らなかったファイルへの他のハード リンクがあった場合)。
何もない。
前の./a.out
プロセスは、の内容をメモリにマップa.out
します(さまざまなセクションで、でそれらを見ることができます/proc/$PID/smaps
)。
後者は、既存のファイルのリンクをg++ program.cpp
解除a.out
し、同じ名前の新しいファイルを作成します。以前の実行可能ファイルがまだメモリにマップされている以前のファイルは変更されません。
Unixでは、古いファイルを閉じると削除されますが、Windowsでは、実行可能ファイルを目的の場所にコピーできないというエラーがスローされます。