#c #linux #unix
#c #linux #unix
Вопрос:
В групповом выступлении я был заинтригован этим вопросом —
Почему стандарт UNIX требует гарантии выделения только самого низкого доступного файлового дескриптора для процесса?
И единственным возможным ответом, о котором я мог подумать, была масштабируемость. Поскольку мы всегда выбираем наименее доступный дескриптор, используемая часть растрового изображения дескриптора в основном плотная и, следовательно, рост массива происходит медленнее.
Мне просто интересно, есть ли какие-либо другие причины, о которых я не знаю.
Кроме того, есть ли у нас какие-либо сценарии, в которых можно сделать логические выводы (те, которые мы можем использовать в программе), если мы знаем, что данный дескриптор больше / меньше другого. Однако мое понимание не позволяет использовать такой метод, поскольку он не гарантирует возраст дескриптора.
Ответ №1:
Существуют различные причины, но конечная из них — «потому что так делалось всегда».
- Легко отследить список файловых дескрипторов, чтобы найти первый неиспользуемый.
- Это определено. Это было важно до того, как
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 тысяч команд в секунду.