Функции блокирования можно использовать в следующих режимах:
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)
{/*Блокировка по записи*/}
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("Ошибка при :
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.