Функции блокирования можно осуществлять в следующих режимах.
С помощью этого режима можно установить, какой вид блокировки применяется к данному файлу:
fd=open(data, O_CREAT|O_WRONLY);
fcntl(fd, F_GETLK, &flptr);
if(flptr.l_type==F_UNLCK)
{/*Данные не блокированы*/}
else if(flptr.l_type==F_RDLCK)
{/*Блокировка по чтению*/}
else if(flptr.l_type==F_WRLCK)
{/*Блокировка по записи*/}
С помощью этой опции организуется блокировка. Если блокирование невозможно, функция fcntl заканчивается и устанавливает переменную errno в заначение EACCES или EAGAIN. С помощью F_SETLK можно также удалить установленную блокировку (F_UNLCK).
flptr.l_whence=SEEK_SET;
flptr.l_len=0;
flptr.l_type=F_RDLCK;
if((fcntl(fd, F_SETLK, &flptr)!=-1)
{/*Установлена блокировка по чтению*/}
flptr.l_start=0;
flptr.l_whence=SEEK_SET;
flptr.l_len=0;
flptr.l_type=F_WRLCK);
if((fcntl(fd, F_SETLK, &sperre)!=-1)
{/*Установлена блокировка по записи*/}
flptr.l_type=F_UNLCK;
if((fcntl(fd, F_SETLK, &flptr)!=-1)
{/*Блокировка снята*/}
С помощью этой команды процесс приостанавливается до тех пор, пока он не сможет организовать необходимую блокировку.
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FNAME "locki.lck"
void status(struct flock *lock)
{
printf("Status: ");
switch(lock->l_type)
{
case F_UNLCK: printf("F_UNLCK (Блокировка снята)\n");
break;
case F_RDLCK: printf("F_RDLCK (pid: %d) (Блокировка по чтению)\n",
lock->l_pid);
break;
case F_WRLCK: printf("F_WRLCK (pid: %d) (Блокировка по записи)\n",
lock->l_pid);
break;
default : break;
}
}
int main(int argc, char **argv)
{
struct flock lock;
int fd;
char buffer[100];
fd = open(FNAME, O_WRONLY|O_CREAT|O_APPEND, S_IRWXU);
memset(&lock, 0, sizeof(struct flock));
/*Проверим, установлена ли блокировка*/
fcntl(fd, F_GETLK, &lock);
if(lock.l_type==F_WRLCK || lock.l_type==F_RDLCK)
{
status(&lock);
memset(&lock,0,sizeof(struct flock));
lock.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &lock) < 0)
printf("Fehler : fcntl(fd, F_SETLK, F_UNLCK) (%s)\n",
strerror(errno));
else
printf("Успешно снята блокировка:
fcntl(fd, F_SETLK, F_UNLCK)\n");
}
status(&lock);
write(STDOUT_FILENO,"\nВВедены данные: ",
sizeof("\nВведены данные: "));
while((read(1,puffer,100))>1)
write(fd,buffer,100);
memset(&lock, 0, sizeof(struct flock));
lock.l_type = F_WRLCK;
lock.l_start=0;
lock.l_whence = SEEK_SET;
lock.l_len=0;
lock.l_pid = getpid();
if (fcntl(fd, F_SETLK, &lock) < 0)
printf("Ошибка при: fcntl(fd, F_SETLK, F_WRLCK)(%s)\n",
strerror(errno));
else
printf("Успешно: fcntl(fd, F_SETLK, F_WRLCK)\n");
status(&lock);
switch(fork())
{
case -1 : exit(0);
case 0 : if(lock.l_type == F_WRLCK)
{
printf("Потомок:Невозможна запись
в файл (F_WRLCK)\n");
exit(0);
}
else
printf("Потомок готов к записи в файл\n") ;
exit(0);
default : wait(NULL); break;
}
close(fd);
return 0;
}
Этот пример показывает возможности сериализации процессов. Тем не менее, здесь все равно существует возможность чтения и записи в процессе-потомке. Такой вариант блокировки называется advisory locking (необязательная блокировка). При его установке не производится никакая дополнительная проверка, должны ли системные функции open, read и write при вызове запрещаться из-за блокировки. Для advisory locking принимается, что пользователь сам является ответственным за проверку того, существуют ли определенные блокировки или нет. Невозможно запретить ВСЕМ процессам доступ к файлу. Только процессы, опрашивающие наличие блокировки с помощью fcntl, блокируются при ее наличии (не всегда).
Для других случаев имеются так называемые строгие блокировки (mandatory locking). Строгие блокировки запрещают процессу получать доступ функциями read или write к данным, которые были блокированы другим процессом ранее через fcntl.
Строгие блокировки можно разрешить, установив бит Set-Group-ID и сняв бит выполнения для группы, например:
{
struct stat statbuffer;
if(fstat(fd, &statbuffer) < 0)
{
fprintf(stderr, "Ошибка при вызове fstat.......\n");
return 0;
}
if(fchmod(fd (statbuffer.st_mode & ~S_IXGRP) | S_ISGID) < 0)
{
fprintf(stderr, "Невозможно установить строгую блокировку...\n");
return 0;
}
return 1;
}
Если с помощью open() открывается файл с флагами O_TRUNC и O_CREAT и для этого файла установлена строгая блокировка, то возвращается ошибка со значением errno=EAGAIN.