В Linux имеется системный вызов flock()
, также реализующий операцию блокирования файла. Но у функции fcntl()
есть большое преимущество: она работает с файловыми системами NFS [28] NFS (Network File System) — популярная технология совместного использования файлов в сети.
(при условии, что сервер NFS имеет относительно недавнюю версию и сконфигурирован правильно). Так что. имея доступ к двум компьютерам, которые монтируют одну и ту же файловую систему через NFS, можно повторить показанный выше пример на двух разных машинах.
8.4. Функции fsync() и fdatasync(): очистка дисковых буферов
В большинстве операционных систем при записи в файл данные не передаются на диск немедленно. Вместо этого операционная система помещает их в резидентный кэш-буфер с целью сокращения числа обращений к диску и повышения оперативности программы. Когда буфер заполнится или произойдет какое-нибудь другое событие (например, истечет определенный промежуток времени), система запишет содержимое буфера на диск в ходе одной непрерывной операции.
В Linux тоже поддерживается такой тип кэширования. Обычно он способствует существенному повышению производительности. Но он же делает ненадежными программы, зависящие от целостности дисковых данных. Если система внезапно выйдет из строя, например вследствие сбоя ядра или отключения питания, любые данные, находящиеся в памяти и еще не записанные на диск, будут потеряны.
Предположим, создается программа обработки транзакций, которая ведет журнальный файл. В этот файл помещаются записи обо всех транзакциях, завершившихся на данный момент, чтобы в случае системного сбоя можно было восстановить целостность данных. Очевидно, не менее важна и целостность самого журнального файла: как только транзакция завершена, запись о ней должна быть немедленно занесена в дисковый файл.
Для реализации такого поведения ОС Linux предоставляет системный вызов fsync()
. Эта функция принимает один аргумент — дескриптор записываемого файла — и принудительно переносит на диск все данные этого файла, находящиеся в кэш-буфере. Функция не завершается до тех пор, пока данные не окажутся на диске.
В листинге 8.3 показана функция, использующая данный системный вызов. Она записывает переданную ей строку в журнальный файл.
Листинг 8.3. ( write_journal_entry.c ) Запись строки в журнальный файл с последующей синхронизацией
#include
#include
#include
#include
#include
const char* journal_filename = "journal.log";
void write_journal_entry(char* entry) {
int fd =
open(journal_filename,
O_WRONLY | O_CREAT | O_APPEND, 0660);
write(fd, entry, strlen(entry));
write(fd, "\n", 1);
fsync(fd);
close(fd);
}
Аналогичное действие выполняет другой системный вызов: fdatasync()
. Но если функция fsync()
гарантирует, что дата модификации файла будет обновлена, то функция fdatasync()
этого не делает, а лишь гарантирует запись данных. В принципе это означает, что функция fdatasync()
способна выполняться быстрее, чем fsync()
, так как ей требуется выполнить одну операцию записи на диск, а не две. Но в настоящее время в Linux обе функции работают одинаково, обновляя дату модификации.
Файл можно также открыть в режиме синхронного ввода-вывода , при котором все операции записи будут немедленно фиксироваться на диске. Для этого в функции open()
следует указать флаг O_SYNC
.
8.5. Функции getrlimit() и setrlimit(): лимиты ресурсов
Функции getrlimit()
и setrlimit()
позволяют процессу определять и задавать лимиты использования системных ресурсов. Аналогичные действия выполняет команда ulimit
, которая ограничивает доступ запускаемых пользователем программ к ресурсам.
У каждого ресурса есть два лимита: жесткий и нежесткий . Второе значение никогда не может быть больше первого, и лишь процессы с привилегиями супер пользователя имеют право менять жесткий лимит. Обычно приложение уменьшает нежесткий лимит, ограничивая потребление системных ресурсов.
Обе функции принимают два аргумента: код, задающий тип ограничения, и указатель на структуру типа rlimit
. Функция getrlimit()
заполняет поля этой структуры, тогда как функция setrlimit()
проверяет их и соответствующим образом меняет лимит. У структуры rlimit
два поля: в поле rlim_cur
содержится значение нежесткого лимита, а в поле rlim_max
— значение жесткого лимита.
Ниже перечислены коды наиболее полезных лимитов, допускающих возможность изменения.
Читать дальше