Почему в UNIX выделяется только самый низкий доступный файловый дескриптор?

#c #linux #unix

#c #linux #unix

Вопрос:

В групповом выступлении я был заинтригован этим вопросом —

Почему стандарт UNIX требует гарантии выделения только самого низкого доступного файлового дескриптора для процесса?

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

Мне просто интересно, есть ли какие-либо другие причины, о которых я не знаю.

Кроме того, есть ли у нас какие-либо сценарии, в которых можно сделать логические выводы (те, которые мы можем использовать в программе), если мы знаем, что данный дескриптор больше / меньше другого. Однако мое понимание не позволяет использовать такой метод, поскольку он не гарантирует возраст дескриптора.

Ответ №1:

Существуют различные причины, но конечная из них — «потому что так делалось всегда».

  1. Легко отследить список файловых дескрипторов, чтобы найти первый неиспользуемый.
  2. Это определено. Это было важно до того, как dup2() вызов стал доступен.

Классически таблица файловых дескрипторов для процесса имела фиксированный размер и была довольно маленькой (20 в 7-м издании Unix, IIRC).

Детерминированный механизм был решающим для перенаправления ввода-вывода в shell. Например:

 cat file1 file2 > file3
  

Оболочка, необходимая для перенаправления стандартного вывода на file3 . Следовательно, он мог бы использовать:

 close(1);  // Standard output
if (open("file3", O_WRONLY|O_CREAT, 0666) != 1)
   …error creating file…
  

и он будет знать, что, поскольку стандартный ввод уже был открыт (файловый дескриптор 0), open() вернет файловый дескриптор 1.

В наши дни вы не можете вывести ничего существенного из значения файлового дескриптора. Я могу написать:

 int fd1 = open(filename, flags, mode);
int fd2 = dup2(fd1, 1024);
close(fd1);
  

и тот факт, что он fd2 (должен) содержать 1024, ничего не говорит вам о порядке, в котором он был открыт по сравнению с файловым дескриптором 3 (который, вероятно, может быть возвращен следующим open() вызовом).

Комментарии:

1. Спасибо. Раньше я думал, что «первый неиспользуемый» можно найти быстрее, если мы используем циклическое распределение.

2. Да, но вы теряете определенность, а определенность важнее скорости, особенно когда в таблице всего 20 файловых дескрипторов (и я думаю, что предел, возможно, был еще ниже в более старых версиях Unix, чем 7-е издание).

Ответ №2:

Если вы закроете стандартный ввод (fd 0), а затем откроете новый файл, он получит fd 0. (Аналогично для fds 1 и 2, stdout и stderr , если нижние fds не были закрыты.) Такая предсказуемость полезна и использовалась во многих программах Unix до того, как dup2 была стандартизирована для перенаправления стандартного ввода / вывода / ошибки в дочернем процессе.

Комментарии:

1. Спасибо. Итак, с этого начинается мой вопрос. Как мы используем эту предсказуемость в программе? Пожалуйста, поясните это.

2. Как указывает @johnathanleffler, в наши дни вы бы использовали dup2 . Но традиционным способом было разветвление, закрытие stdin, открытие того, каким вы хотите, чтобы был перенаправленный stdin (или /dev /null для демона), повторение для stdout и stderr и, наконец, exec.

Ответ №3:

Просто: в 1970 году 64 КБ (65536 байт) были большим количеством. Именно на такой системе была изобретена Unix (если быть точным, PDP-7, которая по умолчанию имела 9 КБ с возможностью обновления до 144 КБ … скажем, за 20 000 долларов).

В такой среде ценен каждый отдельный бит (что объясняет некоторые странные вещи, которые сегодня сбивают с толку избалованных сопляков, такие как использование целых чисел для сохранения указателей и наоборот).

Таким образом, алгоритм попытался бы выделить первый свободный файловый дескриптор в очень маленькой таблице (размер которой на тот момент был фиксированным). Это также позволило бы ускорить завершение работы алгоритма, что также было хорошо, поскольку большинство компьютеров могли выполнять всего несколько 10-100 тысяч команд в секунду.