Вы здесь

Файловые дескрипторы и их дублирование

файловый дескриптор ФД (созданный через вызов open или унаследованный от родительского процесса), является целочисленным индексом в таблице ссылок на структуры открытых файлов процесса. Сама структура, связанная с открытым файлом, содержит дальнейшую ссылку на виртуальный Inode файла в памяти ядра, а так же флаги доступа к файлу (чтение, запись), текущую позицию чтения/записи в файле и некоторые дополнительные данные. Информация о блокировках используется совместно несколькими процессами, а потому вынесена в виртуальный Inode.

По соглашениям, принятым в ОС Unix, в момент запуска программы должны быть открыты ФД 0, 1 и 2, которые интерпретируются как STDIN, STDOUT и STDERR соответственно. Другие ФД так же могут быть открыты, но это никак не регламентируется. При выделении нового ФД при вызове open, pipe, dup и т.п., выбирается наименьший свободный ФД.

Процесс, имея ФД, может создавать на его основе новые ФД, которые будут ссылками на ту же структуру данных в ядре, что и оригинальный ФД и соответственно те же флаги и позицию чтения/записи. Закрытие ФД уменьшает количество ссылок на открытый файл. Фактическое закрытие файла произойдёт тогда, когда на него не будет ссылаться ни один ФД.

Для создания ссылок используются вызовы dup и dup2. dup возвращает первый свободный номер ФД, а dup2 позволяет явно указать номер нового ФД. Если желаемый номер ФД окажется занятым, то он сначала будет закрыт.

int newfd=dup(oldfd)
int newfd=dup2(oldfd,1)

Самое частое использование dup2 это перенаправление стандартного ввода-вывода. Например, shell, выполняя команду:

grep str infile > outfile

может выполнить следующую последовательность действий

Вариант 1:

if (!fork() ){
  // Дочерний процесс для запуска grep

  // Освобождаем ФД==1 (STDOUT)
  close(1);

  // open должен вернуть наименьший свободный ФД т.е. 1
  open("outfile", O_CREAT|OTRUNC|O_WRONLY, 0544);

  // Запускаем программу grep, наследующую STDOUT -> "outfile"
  execlp("grep", "str", "infile",NULL);
}

Вариант 1 в многопоточной среде может привести к гонкам за захват ФД==1, поэтому рекомендуется Варинт2:

if (!fork() ){
  // Дочерний процесс для запуска grep

  // open возвращает какой-то ФД 
  int fd= open("outfile", O_CREAT|OTRUNC|O_WRONLY, 0544);

  // Связываем 1 (STDOUT) с "outfile" через fd
  dup2(fd,1);

  // Освобождаем fd
  close(fd);

  // Запускаем программу grep, наследующую STDOUT -> "outfile"
  execlp("grep", "str", "infile",NULL);
}

Перенаправление через pipe выполняется аналогично.

Яндекс.Метрика