ファイル記述子をclose()するとどうなりますか?


16

ファイル記述子で全体像を取得しようとしています。最初にこれらのファイル記述子を持つprocess1があるとします。

 _process1_
|          |
| 0 stdin  |
| 1 stdout |
| 2 stderr |
|__________|

次に、ファイル記述子1を閉じます。

close(1);

ファイル記述子1 は、カーネルのOpen Files Tableのstdout FILE構造体に変換(ポイント)します

上記のコードでは、ファイル記述子1がプロセスのテーブルから削除され、次のようになります。

 _process1_
|          |
| 0 stdin  |
| 2 stderr |
|__________|

しかし、カーネルではどうなりますか?んstdoutFILE構造体は、割り当て解除を取得しますか?stdoutが特別なファイル(モニター)であり、おそらく他のプロセスで使用されている場合、それはどのように可能ですか?単なる通常のファイル(たとえば.txt)であるFILE構造についてはどうですか?そのようなファイルが他のプロセスで使用されている場合はどうなりますか?

回答:


13

ファイル記述子1は、カーネルのオープンファイルテーブルのstdout FILE構造に変換されます。

これは誤解です。カーネルのファイルテーブルには、ユーザー空間のファイル構造とは何の関係もありません。

いずれにしても、カーネルには2レベルの間接参照があります。ファイル自体を表す内部構造があり、参照カウントされます。参照カウントされる「オープンファイルの説明」があります。そして、参照カウントされないファイルハンドルがあります。ファイル構造は、iノード自体への道を示します。オープンファイルの説明には、オープンモードやファイルポインターなどが含まれます。

closeを呼び出すときは、常にファイルハンドルを閉じます。ファイルハンドルが閉じられると、開いているファイルの説明の参照カウントが減少します。ゼロになると、開いているファイルの説明も解放され、ファイル自体の参照カウントが減少します。ゼロになった場合にのみ、カーネルのファイル構造が解放されます。

共有リソースは参照カウントされるため、あるプロセスが別のプロセスが使用しているリソースを解放することはできません。


あなたの答えの用語を理解するのは少し難しいです。ファイルポインターは「ファイルオフセット」を意味すると推測しています。それはあなたの意図ですか?また、ファイルハンドルとはどういう意味ですか?
オタク14

それは正しい、「ファイルオフセット」とは、後続の読み取りまたは書き込みが発生するオフセットのことです。「ファイルハンドル」は、プロセスと開いているファイルの説明との間のリンクですopen。成功すると、それが返されます。
デビッドシュワルツ14

6

この場合、それほど多くは起こりません。stdin、stdout、およびstderrはすべて、同じファイル記述子のクローンである傾向があります。ファイル記述子の参照カウンターは1つ減ります。通常、同じファイル記述子は、プログラムが実行されたシェルによって保持されるため、ファイル記述子を保持する必要があります。

カーネルは、開いているすべてのファイル(inode)の参照カウントを保持します。参照カウントがゼロより大きい限り、ファイルは保持されます。開いているファイルハンドル用に別のカウンターが保持されると予想します。これがゼロに達すると、カーネルはファイルハンドルが使用したメモリを解放できます。

ファイルへのすべての参照(ディレクトリエントリとファイルハンドル)が削除されると、ファイルシステムコードは再利用のためにiノードをマークします。ファイルのブロックはすべて割り当てに使用できます。多くのファイルシステムは、iノードが解放されると、iノードのブロックポインターをクリアします。これにより、削除されたファイルの回復が困難になります。ディスクへの更新はバッファリングされ、後で完了する場合があります。


1
2つの質問:(1)ファイル記述子は本当に参照カウントされますか?aをcontrol-dするとcat > some.file、猫はstdinでEOFを取得しますが、シェルはそうではありません。(2)なぜ参照カウントですか?なんらかの形式のガベージコレクションを行わないのはなぜですか?GCはユーザー空間ではるかに優れていませんか?
ブルースエディガー

BillThorの答えを拡張:通常の場合、stdin、stdout、およびstderrは、TTYデバイスへのファイルハンドルを開いているだけです。そのため、ファイルハンドルを閉じると、そのTTYデバイスはまだそこにあり、後で再度開くこともできます。
パトリック

1
@BruceEdiger:(1)シェルがcat > some.file実際に実行していることを実行すると、「some.file」を開き、ファイル記述子1に割り当てますexec("cat")。プロセスがexec()されると、開いているファイル記述子を継承します。
パトリック

@BruceEdiger(2)参照カウントは、同じタイプの他のデータ構造へのポインター(または終了するポインターのチェーン)を含まないデータ構造で使用される場合、ガベージコレクションの完全に素晴らしい形式です。また、これはカーネル空間で発生しています(それほど重要ではありません)。
ジル「SO-悪であるのをやめる」
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.