Основы программирования в Linux
3. Выполнение программы даст результат, похожий на следующий:
$ <b>TIMEPORMAT="" time ./copy_system</b>4.67user 146.90system 2:32.57elapsed 99%CPU...$ <b>ls -ls file.in file.out</b>1029 -rw-r--r-- 1 neil users 1048576 Sep 17 10:46 file.in1029 -rw------- 1 neil users 1048576 Sep 17 10:51 file.outКак это работает
Вы используете команду
для определения времени выполнения программы. В ОС Linux переменнаяtimeприменяется для переопределения принятого по умолчанию в стандарте POSIX формата вывода времени, в который не включено время использования ЦПУ. Как видите, что в этой очень старой системе входной файл file.in размером 1 Мбайт был успешно скопирован в файл file.out, созданный с правами на чтение/запись только для владельца. Копирование заняло две с половиной минуты и затратило фактически все доступное время ЦПУ. Программа так медлительна потому, что вынуждена была выполнить более двух миллионов системных вызовов.TIMEFORMATВ последние годы ОС Linux продемонстрировала огромные успехи в повышении производительности системных вызовов и файловой системы. Для сравнения аналогичный тест с применением ядра 2.6 занял чуть менее 14 секунд:
$ <b>TIMEFORMAT="" time ./copy_system</b>2.08user 10.59system 0:13.74elapsed 92%CPU...Упражнение 3.2. Вторая версия программы кодирования файлаВы можете добиться лучших результатов, копируя блоки большего размера. Взгляните на модифицированную программу copy_block.c, которая копирует файл блоками в 1 Кбайт и снова использует системные вызовы.
#include <unistd.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>int main() {<i> char block[1024];</i>int in, out;int nread;in = open("file.in", O_RDONLY);out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);<i> while((nread = read(in, block, sizeof(block))) > 0)</i><i> write(out, block, nread);</i>exit(0);}Теперь испытайте программу, но сначала удалите старый выходной файл.
$ <b>rm file.out</b>$ <b>TIMEFORMAT="" time ./copy_block</b>0.00user 0.02system 0:00.04elapsed 78%CPU...Как это работает
Теперь программа выполняется только сотые доли секунды, поскольку ей требуется около 2000 системных вызовов. Конечно, это время очень зависит от системы, но оно показывает, что системные вызовы сопряжены с поддающимися измерению издержками, поэтому их применение стоит оптимизировать.
Другие системные вызовы для управления файлами
Существует ряд других системных вызовов, оперирующих низкоуровневыми дескрипторами файлов. Они позволяют программе контролировать использование файла, возвращая информацию о его состоянии,
lseekСистемный вызов
задает указатель текущей позиции чтения/записи дескриптора файла, т.е. вы можете применять его для установки в файле места, с которого будет происходить следующее считывание или на которое будет производиться следующая запись. Вы можете задать указатель на абсолютную позицию файла или позицию, относительно текущего положения указателя или конца файла.lseek<b>#include <unistd.h></b><b>#include <sys/types.h></b><b>off_t lseek(int fildes, off_t offset, int whence);</b>Параметр
применяется для указания позиции, а параметрoffsetопределяет способ примененияwhenceи может принимать следующие значения:offset□
—SEEK_SETзадает абсолютную позицию;offset□
—SEEK_CURзадается относительно текущей позиции;offset□
—SEEK_ENDзадается относительно конца файла.offsetВызов
возвращает величину параметраlseekв байтах, измеряемую от начала файла, для которого установлен указатель, или -1 в случае неудачного завершения. Тип данныхoffset, применяемый для параметраoff_tв операциях поиска, — зависящий от реализации типoffset(целое), определенный в файле sys/types.h.integerfstat, stat и lstatСистемный вызов
возвращает информацию о состоянии файла, ассоциированного с открытым дескриптором файла. Эта информация записывается в структуруfstat, адрес которой передается как параметр.bufДалее приведена синтаксическая запись вызовов.
<b>#include <unistd.h></b><b>#include <sys/stat.h></b><b>#include <sys/types.h></b><b>int fstat(int fildes, struct stat *buf);</b><b>int stat(const char *path, struct stat *buf);</b><b>int lstat(const char *path, struct stat *buf);</b>ПримечаниеУчтите, что включение файла sys/types.h не обязательное, но мы рекомендуем включать его при использовании системных вызовов, поскольку некоторые из их определений применяют для стандартных типов псевдонимы, которые могут измениться когда-нибудь.
Родственные функции
иstatвозвращают информацию о состоянии названного файла. Они возвращают те же результаты за исключением того, что файл является символической ссылкой. Вызовlstatвозвращает данные о самой ссылке, а вызовlstat— о файле, на который ссылка указывает.stat