|
Программирование >> Структура ядра и системные вызовы
7.1.14. Функция utime Функция utime изменяет дату и время последнего доступа и модификации файла. Прототип этой функции выглядит следующим образом: #include <sys/types.h> #include <unistd.h> #include <utime.h> int utime ( const char* path name, struct utimbuf* times ); /* время доступа */ /* время модификации */ Аргумент pathname - это путевое имя файла. Аргумент times задает новое время обращения к файлу и новое время его модификации. Структура utimbuf определяется в заголовке <utime.h>: struct utimbuf [ time t actime; time t modtime; }; В POSIX. 1 struct utimbuf определяется в заголовке <utime.h>, a в UNIX System V - в заголовке <sys/types.h>. Тип данных timet соответствует типу данных unsigned long, а сами данные - это количество секунд, прошедших со дня рождения UNIX, т.е. с полудня 1 января 1970 г. по универсальному времени. Если аргумент times задан как О, этот API устанавливает время доступа и время модификации указанного файла равными текущему времени. При этом вызывающий процесс должен иметь право на запись в указанный файл, а эффективный идентификатор его владельца должен совпадать либо с идентификатором владельца файла, либо с идентификатором привилегированного пользователя. Если times - адрес переменной типа struct utimbuf, API устанавливает время доступа и время модификации файла в соответствии со значениями, заданными в этой переменной. При этом эффективный идентификатор владельца вызывающего процесса должен совпадать либо с идентификатором пользователя файла, либо с идентификатором привилегированного пользователя. В случае успешного выполнения utime возвращает О, а в случае неудачи - 1. Причинами неудачи могут быть ошибки, допущенные при задании аргумента path name, отсутствие у процесса прав доступа к указанному файлу, разные владельцы файла и процесса, неверный адрес аргумента times. В приведенной ниже программе testJouch.C с помощью функции utime изменяются время доступа и время модификации файлов. /* Emulate the UNIX touch program */ ♦include <iostream.h> 630SO ♦include <stdio.h> ♦include <sys/types.h> ♦ifaclude <utime.h> ♦intlude <utime.h> int main (int argc, char* argv[]) [ struct utimbuf times; times.actime = times.modtime = time{0); while (-argc 0) /* обработать все указанные файлы */ if (utime (*++argv, stimes)) perror( utime ); return 0; Эта программа определяет переменную times типа struct utimbuf и инициализирует ее значением текущего времени (полученного из вызова функции time). Последующими аргументами командной строки должны быть одно или несколько путевых имен файлов. Для каждого из них программа вызывает функцию utime, которая обновляет время доступа и время модификации. 7.2. Блокировка файлов и записей UNIX-системы позволяют множеству процессов одновременно читать и модифицировать один и тот же файл, что дает им возможность совместно использовать данные. Но при этом возникают и определенные сложности, так как процессу трудно установить, когда данные, находящиеся в интересующем его файле, используются другим процессом. Этот момент особенно важен для таких приложений, как управление базами данных, где ни один процесс не может записывать данные в файл или читать их из файла, к которому в текущий момент осуществляет доступ другой процесс. Чтобы решить эту проблему, в UNIX- и POSIX-системах поддерживается механизм блокировки файлов. Блокировка может применяться только при использовании обычных файлов. Этот механизм позволяет процессу заблокировать файл так, чтобы другие процессы не могли модифицировать его до того, как он будет разблокирован первым процессом. В частности, процесс может установить блокировку записи или блокировку чтения на часть файла или на весь файл. Разница между блокировкой записи и чтения состоит в том, что блокировка записи не позволяет другим процессам устанавливать на блокированную часть файла свои блокировки чтения или записи. Блокировка чтения не позволяет другим процессам устанавливать на эту часть файла только свои блокировки записи. Блокировку чтения эти процессы устанавливать могут. Таким образом, назначение блокировки записи - не давать другим процессам читать заблокированную область файла и записывать в нее данные в течение того времени, когда процесс, который установил блокировку, модифицирует эту область. Блокировку записи называют также исключающей блокировкой. Назначение блокировки чтения - не давать другим процессам записывать данные в заблокированную область в то время, как процесс, который установил блокировку, читает из нее данные. Другим процессам разрешается читать данные из заблокированных областей и блокировать их повторно. Поэтому блокировка чтения называется также разделяемой блокировкой. Следует подчеркнуть, что блокировки, введенные ядром операционной системы, являются обязательными для всех процессов. Если на файл установлена обязательная исключающая блокировка, ни один процесс не может с помощью системных вызовов read и write обращаться к данным в заблокированной области. Точно так же, если на область файла установлена обязательная разделяемая блокировка, ни один процесс не может с помощью системного вызова write изменять данные в заблокированной области. С помощью этих механизмов можно синхронизировать чтение и запись совместно используемых файлов несколькими процессами: если один процесс блокировал файл, то другие процессы, которые хотят записать данные в заблокированные области, блокируются до тех пор, пока первый не снимет блокировку. Обязательные блокировки, однако, могут вызывать проблемы. В частности, если заблудший процесс установил обязательную исключающую блокировку файла и не снимает ее, другие процессы не могут получить доступ к этой области файла до тех пор, пока заблудший процесс не будет уничтожен юти пока система не будет перезагружена. UNIX System V.3 и V.4 поддерживают обязательные блокировки, а BSD UNIX и POSIX-системы - нет. Если блокировка файла не является обязательной, она считается рекомендуемой. Рекомендуемая блокировка не контролируется ядром на уровне системных вызовов. То есть несмотря на то, что для файла установлена блокировка чтения или записи, другие процессы все равно могут обращаться к нему через API read и write. Для обеспечения возможности использовать рекомендуемые блокировки процессы, которые манипулируют одним и тем же файлом, должны согласовать свою работу так, чтобы в каждой операции чтения и записи соблюдалась следующая последовательность: производится попытка блокировать область, к которой будет осуществляться доступ. В случае неудачи процесс может либо подождать, пока запрос блокировки не будет удовлетворен, либо перейти к выполнению других операций и попробовать вновь блокировать файл позже; после блокировки производится чтение заблокированной области или запись в нее; tfiaw: шсд;,*,!,- Atb-iv блокировка снимается. =л?Ц1-арц.\и-М1> s *; л-с.;=и;..ьь Процесс, стараясь при каждой операции установить рекомендуемую блокировку на область файла, с которой он собирается работать, не нарушает этим никакой блокирующей защиты, установленной для этой области другими процессами; другие же процессы не будут модифицировать эту область, пока блокировка не будет снята. После выполнения операции процесс должен сразу же снять все блокировки, которые он установил на файл, чтобы открыть доступ к его ранее заблокированным областям. Рекомендуемая блокировка считается безопасной, поскольку никакой заблудший процесс не сможет принудительно блокировать какой-либо файл, и остальные процессы тлотут продолжать работу, читать данные из файла или записывать данные в фйл после фиксированного числа неудачных попыток блокировки. Недостаток рекомендуемых блокировок состоит в том, что программы, которые создают процессы, осуществляющие совместное использование файлов, должны следовать описанной выше процедуре блокировки файлов, иначе их действия будут несогласованными. Это условие может оказаться трудным для контроля, если программы получены из разных источников (например, от разных поставщиков программного обеспечения). Все UNIX-и POSIX-системы поддерживают рекомендуемые блокировки. Для блокировки файлов в UNIX System V и POSIX.l используется API fcntl. В частности, с помощью этого API можно устанавливать блокировки чтения и записи как на весь файл, так и на отдельный его фрагмент. В BSD UNIX 4.2 и 4.3 интерфейс fcntl возможность блокировки файлов не поддерживает. Прототип API fcntl выглядит следующим образом: #include <fcntl.h> int fcntl ( int fdesc, int cmd flag, ... ); Аргумент fdesc - это дескриптор файла, подлежащего обработке. Аргумент cmd JJag определяет, какую операцию необходимо выполнить. Возмож* ные значения этого аргумента определены в заголовке <fcntl.h>. cmd flag Назначение F SETLK Блокирует файл. Не блокирует, если эта операция сразу не завершается успешно F SETLKW Блокирует файл и блокирует вызывающий процесс на все время, пока действует блокировка на файл F GETLK Делает запрос о том, какой процесс заблокировал указанную область файла При блокировке файлов третьим аргументом функции /си является адрес переменной типа struct flock. Эта переменная задает область файла, где нужно установить, снять блокировку или запросить ее состояние. Структура flock объявляется в <fcntl> следующим образом: struct flock { short l type; /* какую блокировку нужно установить или снять */ short l whence; /* базовый адрес следующего поля */ off t l start; /* смещение относительно базового адреса l whence */ of f t l len; /* сжолько байтов находится в заблокированной области */ Pid t l pid; /* PID процесса, который блокировал файл */ Поле Ijype задает тип устанавливаемой или снимаемой блокировке. Возможные значения этого поля, которые определены в заголовке <fcntl.H>, и соответствующие им функции указаны ниже: Значение Ijtype Использование F RDLCK Устанавливает на указанную область блокировку чтения (разделяемая) F WRLCK Устанавливает на указанную область блокировку записи (исключающая) F UNLCK Снимает блокировку с указанной области Поле IJen задает размер заблокированной области начиная с начального адреса, определенного полями Iwhence и Istart. Если значение 1 1еп - положительное число, то это число является выраженной в байтах длиной заблокированной области. Если lien равно О, то заблокированная область занимает диапазон от начального адреса до заданного системой лимита на максимальный размер файла. Это значит, что при увеличении размера файла действие блокировки распространяется на его расширенную область. Параметр IJen не может иметь отрицательного значения. Переменная типа struct flock определяется и устанавливается процессом до передачи в вызов fcntl. Если аргумент cmd arg вызова fcntl равен F SETLK или F SETLKW, данная переменная определяет область файла, подлежащую блокированию или разблокированию. Если cmdarg = F GETLK, то значение этой переменной используется и в качестве входных данных, и как возвращаемая переменная. В частности, при возвращении из fcntl эта переменная содержит размер и адрес заблокированной области файла и идентификатор процесса, заблокировавшего область. Возвращаемый идентификатор процесса находится в поле / pid этой переменной. Если процесс блокирует файл для чтения, например, начиная с адреса О и по адрес 256, а затем блокирует этот же файл для записи с адреса О по адрес 512, то процесс будет продолжать блокировать только записи с адреса О по адрес 512. Ранее установленная блокировка чтения с О по 256 будет перекрыта блокировкой записи. Этот механизм называется продвижением блокировки. Если процесс теперь разблокирует область файла с 128 по 480, то ему будут принадлежать две блокировки записи: одна с О по 127, а другая с 481 по 512. Этот механизм называется разделением блокировки. Блокировка, установленная функцией fcntl, является рекомендуемой. Обязательные блокировки в POSIX. 1 не поддерживаются. UNIX System V.3 и V.4 в отличие от POSIX позволяют устанавливать с помощью fcntl обязательные блокировки. Чтобы осуществить это, необходимо сначала задать такие атрибуты файла как установление флага set-GID и предоставление права на выполнение для категории фуппа , после чего все блокировки, определяемые функцией fcntl для этого файла, получат статус. \ Чтобы показать, что устанавливаемые на файл блокировки чтения и затиси являются обязательными, в UNIX System V.3 и V.4 можно использовать команду chmod. Эта команда имеет следующий синтаксис: chmod а+1 <имя файла> Все, установленные процессом блокировки файлов при его завершении будут сняты. Если процесс блокирует файл, а затем с помощью функции fork (см. следующую главу) создает порожденный процесс, то последний не наследует блокировку файла, установленную его родителем. В результате успешного выполнения функция fcntl возвращает О, а в случае неудачи возвращает -1. Среди возможных причин неудачи следует назвать ошибку при задании дескриптора файла, конфликт между блокируемой или освобождаемой областью и блокировками, установленными другим процессом, наличие неверных данных в третьем аргументе, достижение установленного системой лимита максимального числа блокировок записей на один файл. Возможность использования функции fcntl блокировки файла показана ниже: ♦include <iostream.h> ♦include <stdio.h> tinclude <sys/types,h tinclude <fcntl.h> tinclude <unistd,.h> int main (int argc, char* argv[]) { : . ./>: -ли struct flock fvar; ; int fdesc; while (-argc > 0) { /* выполнить следующее для каждого файла */ if ((fdesc=open(*++argv.O RDWR))==-!) fvar.l type = F WRLCK; fvar.l whence = SEEK SET; fvar.l start =0; fvar.l len = 0; /* попытка установки исключающей блокировки (блокировки записи) на весь файл */ while (fcntl(fdesc, F SETLK.Sfvar)==-1) /* попытка блокировки неудачна, выяснить, кто заблокировал файл */ while (fcntl(fdesc,F GETLK. sfvar)!=-1 SS , fvar.l type!=F UNLCK) cout *argv locked by fvar.l pid from fvar.l start for . fvar.l len byte for (fvar.l type==F WRLCK ? w : r) << endl; if (!fvar.l ren) break; fvar.l start += fvar.l len; perror( open ); continue;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |