
- •2.1. Введение
- •2.2. Вопросы, относящиеся к команде who
- •2.2.1. Программы состоят из команд
- •2.3. Вопрос 1: Что делает команда who?
- •2.3.1. Обращение к справочнику
- •2.4. Вопрос 2: Как работает команда who?
- •2.4.1. Мы теперь знаем, как работает who
- •2.5. Вопрос 3: Могу ли я написать who?
- •2.5.1. Вопрос: Как я буду читать структуры из файла?
- •2.5.2. Ответ: Использование open, read и close
- •2.5.3. Написание программы who 1.С
- •2.5.4. Отображение записей о вхождениях в систему
- •2.5.5. Написание версии who2.С
- •2.6. Проект два: Разработка программы ср (чтение и запись)
- •2.6.1. Вопрос 1: Что делает команда ср?
- •2.6.2. Вопрос 2: Как команда ср создает файл и как пишет в него? Создание/транкатенация файла
- •2.6.3. Вопрос 3: Могу ли я написать программу ср?
- •2.6.4. Программирование в Unix кажется достаточно простым
- •2.7. Увеличение эффективности файловых операций ввода/ вывода: Буферирование
- •2.7.1. Какой размер буфера следует считать лучшим?
- •2.7.2 Почему на системные вызовы требуется тратить время?
- •2.7.3. Означает ли, что наша программа who2.С неэффективна?
- •2.7.4. Добавление буферирования к программе who2.С
- •2.8. Буферизация и ядро
- •2.8.1. Если буферизация столь хороша, то почему ее не использует ядро?
- •2.9. Чтение файла и запись в файл
- •2.9.1. Выход из системы: Что происходит?
- •2.9.2. Выход из системы: Как это происходит
- •2.9.3. Смещение текущего указателя: Iseek
- •2.9.4. Кодирование выхода из системы через терминал
- •2.10. Что делать с ошибками системных вызовов?
- •3.1. Введение
- •3.2. Вопрос 1: Что делает команда is?
- •3.2.1. Команда Is выводит список имен файлов и оповещает об атрибутах файлов
- •3.2.3. Наиболее употребимые опции
- •3.2.4. Первый ответ: Итоговые замечания
- •3.3. Краткий обзор дерева файловой системы
- •3.4. Вопрос 2: Как работает команда Is?
- •3.4.1. Что же такое каталог, в конце концов?
- •3.4.2. Работают ли системные вызовы open, read и close в отношении каталогов?
- •3.4.3. Хорошо, хорошо. Но как же мне прочитать каталог?
- •3.5. Вопрос 3: Могу ли я написать Is?
- •3.5.1. Что еще нужно делать?
- •3.6. Проект 2: Написание версии Is -I
- •3.6.1. Вопрос 1: Что делает Is-I?
- •3.6.2. Вопрос 2: Какработает Is -I?
- •3.6.3. Ответ: Системный вызов stat получает информацию о файле
- •3.6.4. Какую еще информацию можно получить с помощью системного вызова stat?
- •3.6.5. Чего мы достигли?
- •3.6.6. Преобразование числового значения поля mode в символьное значение
- •3.6.7. Преобразования числового представления идентификаторов собственника/группы в строковое представление
- •3.6.8. Объединение всего вместе: Is2.C
- •3.7. Три специальных разряда
- •3.7.1. Разряд Set-User-id
- •3.7.2Разряд Set-Group-id
- •3.7.3 Разряд Sticky Bit
- •3.7.4. Специальные разряды nls-l
- •3.8. Итоги для команды is
- •3.9. Установка и модификация свойств файла
- •3.9.1. Тип файла
- •3.9.2. Разряды прав доступа и специальные разряды
- •3.9.3. Число ссылок на файл
- •3.9.4. Собственник и группа для файла
- •3.9.5. Размер файла
- •3.9.6. Время последней модификации и доступа
- •3.9.7. Имя файла
2.6.4. Программирование в Unix кажется достаточно простым
Программа who - это программа, которая читает из файла и форматирует данные. Программа ср - это программа, которая читает один файл и производит запись в другой файл.Обе программы используют одни и те же базовые системные вызовы для установления язей с файлами и организации передачи данных в файлы и из файлов. Из справочника и изз текстов заголовочных файлов мы будем извлекать всю информацию, которая будет обходима, чтобы понять, как писать такие программы.
Программирование в Unix не выглядит слишком затруднительным. Следует ли пропустить некоторые основополагающие вопросы? Давайте разберемся. Помимо трех вопросов, которые мы сформулировали в отношении Unix к программирования в Unix, есть еще ин важный вопрос: что можно сделать, чтобы это работало лучше?
2.7. Увеличение эффективности файловых операций ввода/ вывода: Буферирование
В программе ср1 содержится символьная константа BUFFERSIZE, которая задает размер массива в байтах, где содержатся данные по мере их передачи от исходного файла к целевому файлу. Это значение равно 4096. Возникает важный вопрос: какой размер буфера следует считать лучшим?
2.7.1. Какой размер буфера следует считать лучшим?
Давайте порассуждаем. Если вы используете половник для разлива супа по тарелкам, чем больше будет этот половник, тем меньше вам потребуется манипуляций с разливом меньше времени.
Рассмотрим файл длиной в 2500 байт. Можно выделить некоторые особенности при работе с ним:
Ех: Размер файла = 2500 bytes
Если buffer = 100 байт, тогда для копирования потребуется 25 системных вызовов read() и 25 write()
Если buffer = 1000 байт, тогда
для копирования потребуется 3 системных вызова read() и 3 write()
При изменении размера буфера со 100 байт до 1000 байт сокращается число системных вызовов read и write с 50 до 6.
В следующей ниже таблице показано время выполнения программы ср1 при копировании файла размером в 5 Мбайт при различных значениях BUFFERSIZE.
Размер буфера |
Время выполнения в секундах |
1 |
50.29 |
4 |
12.81 |
16 |
3.28 |
64 |
0.96 |
128 |
0.56 |
256 |
0.37 |
512 |
0.27 |
1024 |
0,22 |
Размер буфера |
Время выполнения в секундах |
2048 |
0.19 |
4096 |
0.18 |
8192 |
0.18 |
16384 |
0.18 |
Системные вызовы требуют время для своего выполнения. Программа, где делается больше системных вызовов, работает медленнее и отнимает время у других пользователей, которые хотели бы работать в системе.
2.7.2 Почему на системные вызовы требуется тратить время?
Чем определяются временные затраты при работе системных вызовов? На рисунке 2.5 схематично показан поток управления.
Рисунок 2.5
Поток управления при работе системных вызовов
На рисунке изображена память. Процесс развивается в пользовательской памяти, а ядро, располагается в системном пространстве. Диск доступен для ядра. Наша программа ср1 хочет читать данные, поэтому она обращается с системным вызовом read к ядру для чтения данных. Код, который производит фактическую передачу данных процессу с диска, является частью ядра. Поэтому управление от вашего кода в пользовательском пространстве будет передано коду ядра, находящемуся в системном пространстве. После этого процессор будет выполнять ту часть кода ядра, который организует передачу данных. На выполнение кода по передаче данных требуется время.
Но время требуется не только на передачу данных. Время требуется также и на переход в ядро и выход из ядра. Когда исполняется код ядра, процессор работает в супервизорном режиме со специальным стеком и памятью. При исполнении пользовательского кода процессор работает в пользовательском режиме.
Функции ядра должны иметь доступ к диску, терминалам, принтерам и другим ресурсам.
А вот пользовательские функции не должны иметь доступа к этим ресурсам. Поэтому и организуется работа компьютера в различных режимах. Когда компьютер работает в пользовательском режиме, он имеет ограничение на доступ к памяти - возможен доступ только к определенному сегменту памяти в пользовательском пространстве. Когда происходит работа в режиме ядра, компьютер имеет доступ ко всей памяти. Особенности смены режимов работы зависят от вашего процессора. У каждого процессора имеются собственные схемы по поддержке супервизорного и пользовательского режимов. Каждая версия Unix адаптируется к той модели поддержания супервизорного и пользовательских режимов, которые обеспечиваются данным процессором.
Рассмотрим Кларка Кента и Супермена. Когда происходит переход от пользовательского режима (Кларк Кент) в режим ядра (Супермен), то Кларк находит телефонную будку, там переодевается, снимает очки и меняет прическу. Далее Супермен выполняет определенные действия, на что требуется время. И на переход обратно в пользовательский режим также требуется время. Чем чаще Кларк Кент выполняет такие смены образов (режимов),| тем больше времени у него на это уходит и меньше времени остается на работу репортером или на борьбу с преступностью.
Ваша программа не является исключением. Чем больше времени процессор затрачивает ; на исполнение кода ядра и на вход в режим ядра и на выход из него, тем меньше времени у него остается для работы над вашим кодом или на обеспечение неких системных сервисов. Поскольку за время следует платить, то системные вызовы называют дорогими. Что приводит к удорожанию при чтении и записи данных в нашей версии программы who?