Що відбувається, коли я закриваю () дескриптор файлу?


16

Я намагаюся отримати всю картину з дескрипторами файлів. Скажіть, у мене є process1, який спочатку має такі дескриптори файлів:

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

Потім закриваю дескриптор файлу 1:

close(1);

Дескриптор 1 файлу переводить (вказує на) структуру FILE stdout у таблиці відкритих файлів ядра .

З кодом вище, дескриптор 1 файлу видаляється з таблиці процесу, яка стає:

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

Але що відбувається в ядрі? Чи stdoutдістається структура FILE? Як це можливо, якщо stdout є спеціальним файлом (монітором) і, ймовірно, використовується іншими процесами? Що з структурами FILE, які є лише звичайними файлами (наприклад, .txt)? Що робити, якщо такий файл використовується іншим процесом?

Відповіді:


13

Дескриптор 1 файлу перекладається на структуру FILE stdout у таблиці відкритих файлів ядра.

Це непорозуміння. Таблиця файлів ядра не має нічого спільного з структурами файлів простору користувачів.

У будь-якому випадку ядро ​​має два рівні непрямості. Існує внутрішня структура, яка представляє сам файл, яка посилається на облік. Існує "відкритий опис файлу", який посилається. А потім є ручка файлу, яка не посилається. Структура файлу вказує шлях до самої inode. Опис відкритого файлу містить такі речі, як відкритий режим та вказівник на файл.

Коли ви телефонуєте закрити, ви завжди закриваєте ручку файлу. Коли ручка файлу закрита, кількість посилань на її відкритий опис файлу зменшується. Якщо вона переходить до нуля, відкривається також опис відкритого файлу, а кількість посилань на сам файл зменшується. Тільки якщо це дорівнює нулю, звільняється структура файлу ядра.

Немає шансів, щоб один процес випустив ресурс, який використовує інший процес, оскільки загальні ресурси враховуються.


У мене є невеликі труднощі з розумінням термінології у вашій відповіді. Я здогадуюсь, що покажчик файлу означає "зміщення файлу". Це ви мали на увазі? Також що ви мали на увазі під ручкою файлу ?
Geek

Це правильно, під "зміщенням файлу" я маю на увазі зміщення, при якому відбудеться подальше читання чи запис. "Ручка файлу" - це посилання між процесом і відкритим описом файлу - це те, що ви отримуєте назад, коли openдосягаєте успіху.
Девід Шварц

6

У цьому випадку не багато буде. stdin, stdout та stderr, як правило, є клонами одного і того ж дескриптора файлів. Контрольний лічильник дескриптора файлів зменшиться на одиницю. Один і той же дескриптор файлів зазвичай утримується оболонкою, з якої запускалася програма, тому дескриптор файлів потрібно зберігати.

Ядро зберігає підрахунок посилань для всіх відкритих файлів (inodes). Поки кількість посилань більше нуля, файл буде зберігатися. Я б очікував, що окремий лічильник зберігається для відкритих ручок файлів. Як тільки це досягне нуля, ядро ​​може звільнити пам'ять, яку використовує обробка файлу.

Коли всі посилання на файл (записи каталогів та ручки файлів) були видалені, код файлової системи позначатиме inode для повторного використання. Будь-які блоки файлу доступні для розподілу. Багато файлових систем очистять блок-покажчики в inode при його випуску. Це ускладнює відновлення видаленого файлу. Оновлення диска можуть бути завантажені та завершені в більш пізній час.


1
Два питання: (1) чи справді дефіктори файлів перераховані? Коли ви керуєте-d a cat > some.file, кішка отримує EOF на stdin, але оболонка ні. (2) Чому підрахунок посилань? Чому б не якась форма збору сміття? Чи не GC набагато кращий у користувальницькому просторі?
Брюс Едігер

Розширення на відповідь BillThor: У звичайних випадках stdin, stdout та stderr - це лише відкриті ручки файлів на TTY-пристрої. Тож якщо ви закриєте ручку файлу, пристрій TTY все ще є, і його можна буде знову відкрити знову.
Патрік

1
@BruceEdiger: (1) коли оболонка запускає cat > some.fileте, що її насправді робить, розщеплює, відкриває 'some.file' і призначає його дескриптору 1, то це робить exec("cat"). Коли процес є exec () 'd, він успадковує дескриптори відкритого файлу.
Патрік

@BruceEdiger (2) Підрахунок посилань - це прекрасна форма збору сміття, коли він використовується в структурах даних, які не містять вказівників на (або ланцюжки покажчиків, що закінчуються) інших структур даних того ж типу. Також це відбувається в просторі ядра (не те, що це має велике значення).
Жил "ТАК - перестань бути злим"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.