Unix профессиональное программирование Второе издание У. Ричард Стивене, Стивен а раго 2007 Серия «High tech» У. Ричард Стивене, Стивен А. Раго




Скачать 17.46 Mb.
НазваниеUnix профессиональное программирование Второе издание У. Ричард Стивене, Стивен а раго 2007 Серия «High tech» У. Ричард Стивене, Стивен А. Раго
страница14/143
Дата конвертации11.01.2013
Размер17.46 Mb.
ТипДокументы
1   ...   10   11   12   13   14   15   16   17   ...   143
Глава 3. Файловый ввод-вывод

Запись в таблице процессов





Таблица виртуальных узлов


Текущий размер файла




Флаги Указатель

дескрип- на таблицу

тора файлов




W0: Ml: fd2: fd3:








































Запись в таблице процессов



t флаги Указатель дескрип- на таблицу тора файлов




fdO: fdl: fd2: fd3: fd4:














































Таблица файлов

Флаги состояния файла

Текущая позиция файла

Указатель на виртуальный узел

Флаги состояния файла

Текущая позиция файла

Указатель на виртуальный узел

Информация виртуального узла

Информация индексного узла

Рис. 3.2. Два независимых процесса открыли один и тот же файл

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

Если файл был открыт с флагом 0_APPEND, соответствующий флаг устанав­ливается в таблице файлов. Каждый раз при выполнении операции запи­си в качестве текущей позиции принимается значение размера файла из таблицы индексных узлов. В результате запись всегда производится в конец файла.

Если текущая позиция переносится в конец файла с помощью функции lseek, выполняется только перезапись значения текущего размера файла из таблицы индексных узлов в поле текущей позиции в таблице файлов. (Обратите внимание: это не то же самое, что открытие файла с флагом 0_APPEND, о чем мы будем говорить в разделе 3.11.)

Функция lseek изменяет только значение текущей позиции файла в таб­лице файлов. Никаких операций ввода-вывода при этом не производится.

3.11. Атомарные операции

113

Существует возможность открыть несколько дескрипторов, которые будут ссылаться на одну и ту же запись в таблице файлов; мы увидим это в разде­ле 3.12 при обсуждении функции dup. То же самое происходит в результате вызова функции fork, когда родительский и дочерний процессы совместно используют одни и те же записи в таблице файлов для каждого из открытых дескрипторов (раздел 8.3).

Обратите внимание на различия, которые существуют между флагами деск­риптора и флагами состояния файла. Флаги дескриптора уникальны для ка­ждого отдельно взятого дескриптора, открытого процессом, тогда как флаги состояния файла имеют отношение ко всем дескрипторам в любом процессе, которые ссылаются на одну и ту же запись в таблице файлов. Рассматривая функцию fcntl в разделе 3.14, мы узнаем, как можно получить и изменить значения флагов дескриптора и флагов состояния файла.

Все описанное ранее в этом разделе прекрасно работает в том случае, когда несколько процессов читают данные из одного и того же файла. Каждый процесс имеет собственную запись в таблице файлов со своим собственным значением текущей позиции файла. Однако можно получить совершенно не­ожиданные результаты, если несколько процессов попытаются выполнить запись данных в один и тот же файл. Чтобы избежать в будущем неприят­ных сюрпризов, мы должны разобраться с понятием атомарности операций.

3.11. Атомарные операции Добавление данных в конец файла

Рассмотрим процесс, который дописывает данные в конец файла. Старые версии UNIX не поддерживали флаг 0_APPEND для функции open, в результате приходилось писать нечто вроде:

if (lseek(fd, OL, 2) < 0) /* переместить текущую позицию в конец файла */

err_sys("ошибка вызова функции lseek");
if (write(fd, buf, 100) != 100) /* и выполнить запись */


егr_sys("ошибка вызова функции write");

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

Допустим, существуют два независимых процесса А и В, которые выполня­ют запись данных в конец одного и того же файла. Каждый из процессов от­крыл файл, но без флага 0_APPEND. Эта ситуация изображена на рис. 3.2. Ка­ждый процесс имеет собственную запись в таблице файлов, но при этом они ссылаются на одну и ту же запись в таблице виртуальных узлов. Предполо­жим, что процесс А вызывает функцию lseek и устанавливает текущую по­зицию файла в значение 1500 (текущий размер файла). Затем ядро приоста­навливает работу процесса А и передает управление процессу В, который

114

Глава 3. Файловый ввод-вывод

в свою очередь также вызывает функцию 1 seek и также устанавливает теку­щую позицию файла в значение 1500 (текущий размер файла). После этого процесс В вызывает функцию write, которая увеличивает текущую позицию файла до 1600. Поскольку размер файла был увеличен, ядро записывает но­вое значение размера файла (1600) в таблицу виртуальных узлов. После это­го ядро опять переключает процессы и передает управление процессу А. Ко­гда процесс А вызывает функцию write, запись будет выполняться с места, на которое указывает значение текущей позиции файла для процесса А, то есть 1500. В результате данные окажутся записанными поверх тех, что за­писаны процессом В.

Проблема в том, что операция «перейти в конец файла и записать данные» требует обращения к двум отдельным функциям (как мы только что показа­ли). Решением проблемы было бы атомарное1 выполнение операции пози­ционирования и записи. Любая операция, которая требует обращения более чем к одной функции, не может быть атомарной, поскольку всегда сущест­вует вероятность того, что ядро временно приостановит процесс между дву­мя последовательными вызовами функций (как это было показано выше).

ОС UNIX предоставляет возможность атомарного выполнения этой опера­ции, если мы укажем флаг 0_APPEND при открытии файла. Как мы уже гово­рили в предыдущем разделе, этот флаг заставит ядро выполнять перенос те­кущей позиции в конец файла непосредственно перед операцией записи. А кроме того, отпадает необходимость вызывать функцию lseek перед каж­дым вызовом функции write.

Функции pread и pwrite

Стандарт Single UNIX Specification включает в себя расширения XSI, кото­рые позволяют процессам атомарно выполнять операции перемещения те­кущей позиции и ввода-вывода. Эти расширения представлены функциями

pread и pwrite.

#include

ssize_t pread(int filedes, void *buf, size J: nbytes, off_t offset);

Возвращает количество прочитанных байт, 0 по достижении конца файла и -1 в случае ошибки

ssize_t pwrite(int filedes, const void *buf, size_t nbytes, off_t offset);

Возвращает количество записанных байт или -1 в случае ошибки

Вызов функции pread эквивалентен двум последовательным вызовам функ­ций lseek и read со следующими отличиями:

• При использовании pread нет возможности прервать выполнение этих двух операций

То есть неделимое. - Примеч. перев.

3.12. Функции dup и dup2

115

• Значение текущей позиции файла не изменяется

Вызов функции pwrite эквивалентен двум последовательным вызовам функ­ций lseek и write с аналогичными отличиями.

Создание файла

Пример еще одной атомарной операции мы видели при описании флагов 0_CREAT и 0_EXCL функции open. При одновременном указании обоих флагов функция open будет завершаться ошибкой, если файл уже существует. Мы также говорили, что проверка существования файла и создание файла будут выполняться атомарно. Если бы не было такой атомарной операции, мы могли бы попробовать написать нечто вроде:

if ((fd = open(pathname, 0_WR0NLY)) < 0) { if (errno == ENOENT) {

if ((fd = creat(pathname, mode)) < 0)

err_sys("ошибка вызова функции creat"); } else {

err_sys("ошибка вызова функции open"); > }

Эта ситуация чревата проблемами, если файл с тем же именем будет создан другим процессом между обращениями к функциям open и creat. Если дру­гой процесс создаст файл между вызовами этих функций и успеет туда что-либо записать, то эти данные будут утеряны, когда первый процесс вызовет функцию creat. Объединение проверки существования файла и его создания в единую атомарную операцию решает эту проблему.

Вообще говоря, термин атомарная операция относится к таким операциям, которые могут состоять из нескольких действий. Если операция атомарна, то либо все необходимые действия будут выполнены до конца, либо не будет выполнено ни одно из них. Атомарность не допускает выполнения лишь не­которой части действий. К теме атомарных операций мы еще вернемся, ко­гда будем рассматривать функцию link (раздел 4.15) и блокировку отдель­ных записей в файле (раздел 14.3).

3.12. функции dup и dup2

Дубликат дескриптора существующего файла можно создать с помощью од­ной из следующих функций:

#include

int dup(int filedes)',

int dup2(int filedes, int filedes2)\

Возвращают новый дескриптор файла или -1 в случае ошибки

116

Глава 3. Файловый ввод-вывод

функция dup гарантирует, что возвращаемый ею новый файловый дескрип­тор будет иметь наименьшее возможное значение. При вызове функции dup2 мы указываем значение нового дескриптора в аргументе filedes2. Если деск­риптор filedes2 перед вызовом функции уже был открыт, то он предвари­тельно закрывается. Если значения аргументов filedes и filedes2 эквива­лентны, то функция dup2 вернет дескриптор f iledes2, не закрывая его.

Новый файловый дескриптор, возвращаемый функциями, будет ссылаться на ту же самую запись в таблице файлов, что и дескриптор filedes. Проде­монстрируем это на рис .3.3.

Запись в таблице процессов

Флаги Указатель

дескрип- на таблицу

тора файлов




fdO: fd 1:

fd2: fd3:








































Таблица файлов

Флаги состояния файла

Текущая позиция файла

Указатель на виртуальный узел

Таблица виртуальных узлов

Информация виртуального узла

Информация индексного узла

Текущий размер файла

Рис. 3.3. Структуры в ядре после вызова функции dup(l)

На рисунке предполагается, что процесс при запуске выполняет код

newfd = dup(1);

Предполагается, что следующий доступный дескриптор - это число 3 (что наиболее вероятно, потому что командная оболочка уже открыла для про­цесса дескрипторы 0, 1 и 2). Поскольку оба дескриптора указывают на одну и ту же запись в таблице файлов, они совместно будут использовать флаги состояния файла - чтение, запись, добавление в конец файла и прочие, и те­кущая позиция файла будет для них также одинаковой.

Каждый из дескрипторов будет иметь свой собственный набор флагов деск­риптора. Как мы увидим в следующем разделе, функция dup всегда сбрасы­вает флаг close-on-exec («закрыть-при-вызове-ехес») в новом дескрипторе.

Дубликат дескриптора можно создать также с помощью функции fcntl, ко­торая будет описана в разделе 3.14. На самом деле вызов

dup(filedes); эквивалентен вызову

fcntl(filedes, F.DUPFD, 0); Аналогично вызов

dup2(filedes, filedes2);

3.13. Функции sync, fsync и fdatasync

117

эквивалентен вызову

close(filedes2);

fcntl(filedes, F_DUPFD, filedes2);

В последнем случае для функции dup2 приведен не совсем точный эквива­лент из двух последовательных вызовов функций close и fcntl. Имеются сле­дующие различия:

  1. Функция dup2 представляет собой атомарную операцию, тогда как аль­тернативная форма состоит из обращений к двум функциям. В результате возникает вероятность того, что между обращениями к функциям close и fcntl будет вызван обработчик сигнала, который изменит дескриптор файла. (Сигналы будут обсуждаться в главе 10.)

  2. Существуют некоторые отличия в кодах ошибок, возвращаемых через ег-гпо функциями dup2 и fcntl.

Системный вызов dup2 впервые появился в Version 7 и затем перекочевал в BSD. Воз­можность создания дубликатов дескрипторов с помощью fcntl появилась в System III и перешла в System V. В SVR3.2 была включена функция dup2, а в 4.2BSD - функция fcntl и функциональность F_DUPFD. Стандарт P0SIX.1 требует как наличия функции dup2,TaK и поддержки функцией fcntl параметра F_DUPFD.

3.13. Функции sync, fsync и fdatasync

Традиционные реализации UNIX имеют в своем распоряжении буферный кэш или кэш страниц, через который выполняется большинство дисковых операций ввода-вывода. Когда мы записываем данные в файл, они, как пра­вило, сначала помещаются ядром в один из буферов, а затем ставятся в оче­редь для записи на диск в более позднее время. Этот прием называется отло­женной записью. (В главе 3 [Bach 1986] детально рассматривается работа бу­ферного кэша.)

Ядро обычно записывает отложенные данные на диск, когда возникает необ­ходимость в повторном использовании буфера. Для синхронизации файло­вой системы на диске и содержимого буферного кэша существуют функции

sync, fsync и fdatasync.

tfinclude int fsync(int filedes); int fdatasync(int filedes);

Возвращают значение 0 в случае успеха, -1 в случае ошибки

void sync(void);

Функция sync просто ставит все измененные блоки буферов в очередь для за-писи и возвращает управление - она не ждет, пока физически будет выпол­нена запись на диск.

118

1   ...   10   11   12   13   14   15   16   17   ...   143

Похожие:

Unix профессиональное программирование Второе издание У. Ричард Стивене, Стивен а раго 2007 Серия «High tech» У. Ричард Стивене, Стивен А. Раго iconСтивене Д. 80 Сознавание: исследуем, экспериментируем, упражняемся/ Пер с англ. А. Пилюгина
Разработка серийного оформления художника В. Щербакова Серия основана в 1999 году

Unix профессиональное программирование Второе издание У. Ричард Стивене, Стивен а раго 2007 Серия «High tech» У. Ричард Стивене, Стивен А. Раго iconРичард Д. Деловые культуры в международном бизнесе. От столкновения к взаимопониманию / Льюис Ричард Д.; пер с англ. Т. А. Нестика
Европа: вчера, сегодня, завтра / ран, Ин-т Европы; отв ред., авт предисл. Н. П. Шмелев. – М.: Экономика, 2002. – 823с

Unix профессиональное программирование Второе издание У. Ричард Стивене, Стивен а раго 2007 Серия «High tech» У. Ричард Стивене, Стивен А. Раго iconРичард Докинз. Эгоистичный ген
Ричард Докинз профессор Оксфордского университета, автор таких известных книг, как "Эгоистический ген", "Слепой часовщик", "Расширенный...

Unix профессиональное программирование Второе издание У. Ричард Стивене, Стивен а раго 2007 Серия «High tech» У. Ричард Стивене, Стивен А. Раго iconСтивен Кинг После заката Стивен Кинг После заката Посвящается Хайди Питлор
Он, бесформенный, присвоил чужую форму. Как такое могло случиться, Остин? Нет, как такое может быть? И почему тогда солнце не померкнет,...

Unix профессиональное программирование Второе издание У. Ричард Стивене, Стивен а раго 2007 Серия «High tech» У. Ричард Стивене, Стивен А. Раго iconРичард Флорида, «Креативный класс: люди, которые меняют будущее». М
Ричард Флорида, «Креативный класс: люди, которые меняют будущее». М.: Классика-xxi, 2005. (Richard Florida, “The Rise of The Creative...

Unix профессиональное программирование Второе издание У. Ричард Стивене, Стивен а раго 2007 Серия «High tech» У. Ричард Стивене, Стивен А. Раго iconРичард Фарсон Менеджмент абсурда. Парадоксы лидерства Публикуется по: © "София", 2001 Перевод с англ. © А. Левицкий Об
Роджерсом (одним из этих проектов был получивший академическую премию документальный фильм "Путешествие в себя"). Ричард Фарсон получил...

Unix профессиональное программирование Второе издание У. Ричард Стивене, Стивен а раго 2007 Серия «High tech» У. Ричард Стивене, Стивен А. Раго iconThe Roles of Intermediaries in Cluster Development: The Thai Experiences from High-Tech and mid-tech manufacturing, knowledge-intensive services, to

Unix профессиональное программирование Второе издание У. Ричард Стивене, Стивен а раго 2007 Серия «High tech» У. Ричард Стивене, Стивен А. Раго iconHigh School/High Tech Program Guide

Unix профессиональное программирование Второе издание У. Ричард Стивене, Стивен а раго 2007 Серия «High tech» У. Ричард Стивене, Стивен А. Раго iconКультура Социогуманитарные исследования Издание второе, дополненное
Борисов С. Б. Человек. Текст. Культура. Социогуманитарные исследования. Издание второе, дополненное. – Шадринск, 2007 – 556 с

Unix профессиональное программирование Второе издание У. Ричард Стивене, Стивен а раго 2007 Серия «High tech» У. Ричард Стивене, Стивен А. Раго iconЕстественно-математические науки. Техника Барр, С. Россыпи головоломок [Текст] / Стивен Барр; пер с англ. Ю. Н. Сударева. М. Мир, 1987. 415 с
Барр, С. Россыпи головоломок [Текст] / Стивен Барр; пер с англ. Ю. Н. Сударева. М. Мир, 1987. 415 с


Разместите кнопку на своём сайте:
lib.convdocs.org


База данных защищена авторским правом ©lib.convdocs.org 2012
обратиться к администрации
lib.convdocs.org
Главная страница