Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Books
  Краткое описание
 Linux
 W. R. Стивенс TCP 
 W. R. Стивенс IPC 
 A.Rubini-J.Corbet 
 K. Bauer 
 Gary V. Vaughan 
 Д Вилер 
 В. Сталлинг 
 Pramode C.E. 
 Steve Pate 
 William Gropp 
 K.A.Robbins 
 С Бекман 
 Р Стивенс 
 Ethereal 
 Cluster 
 Languages
 C
 Perl
 M.Pilgrim 
 А.Фролов 
 Mendel Cooper 
 М Перри 
 Kernel
 C.S. Rodriguez 
 Robert Love 
 Daniel Bovet 
 Д Джеф 
 Максвелл 
 G. Kroah-Hartman 
 B. Hansen 
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Linux Kernel 2.6...5170 
 Trees...940 
 Максвелл 3...871 
 Go Web ...823 
 William Gropp...803 
 Ethreal 3...787 
 Gary V.Vaughan-> Libtool...773 
 Ethreal 4...771 
 Rodriguez 6...765 
 Ext4 FS...755 
 Clickhouse...754 
 Steve Pate 1...754 
 Ethreal 1...742 
 Secure Programming for Li...732 
 C++ Patterns 3...716 
 Ulrich Drepper...697 
 Assembler...695 
 DevFS...662 
 Стивенс 9...649 
 MySQL & PosgreSQL...632 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org

Глава 9 , Блокировка записей

Исходники для этой страницы лежат тут

Рассмотрим тип блокировки чтения-записи при совместном доступе к файлу разными программами . Обращение к файлу идет через дескриптор , блокировка активируется с помощью fcntl. Такой тип блокировки может использоваться разными процессами , но не разными потоками одного процесса.

Напишем программу доступа к одному текстовому файлу несколькими процессами. Процесс , выполняющий текущую обработку файла , должен его заблокировать для доступа. Давайте для начала напишем такую версию , которая не будет делать никакой блокировки .

       
 #define	SEQFILE	"seqno"		/* filename */
 
 void	my_lock(int), my_unlock(int);
 
 int main(int argc, char **argv)
 {
 	int		fd;
 	long	i, seqno;
 	pid_t	pid;
 	ssize_t	n;
 	char	line[MAXLINE + 1];
 
 	pid = getpid();
 	fd = Open(SEQFILE, O_RDWR, FILE_MODE);
 
 	for (i = 0; i < 20; i++) {
 		my_lock(fd);				/* lock the file */
 
 		Lseek(fd, 0L, SEEK_SET);	/* rewind before read */
 		n = Read(fd, line, MAXLINE);
 		line[n] = '\0';				/* null terminate for sscanf */
 
 		n = sscanf(line, "%ld\n", &seqno);
 		printf("%s: pid = %ld, seq# = %ld\n", argv[0], (long) pid, seqno);
 
 		seqno++;					/* increment sequence number */
 
 		snprintf(line, sizeof(line), "%ld\n", seqno);
 		Lseek(fd, 0L, SEEK_SET);	/* rewind before write */
 		Write(fd, line, strlen(line));
 
 		my_unlock(fd);				/* unlock the file */
 	}
 	exit(0);
 }
 
Программа пишет число в файл seqno.

Интерфейсом для блокировки записей является функция fcntl

       
 	int fcntl(int fd , int cmd , ... (struct flock * arg))
 
 Возвращаемый результат произволен 
 
Аргумент cmd может принимать 3 значения :
       
 	1  F_SETLK  - установка блокировки или сброс блокировки	
 	2  F_SETLKW - то же , но в ждцщем режиме , пока блокировка будет установлена (wait)
 	3  F_GETLK  - проверка блокировки  
 
Структура flock описывает тип блокировки - чтение или запись - и диапазон блокировки .

Существует 2 способа заблокировать файл целиком :

       
 	1 указать в flock.l_whence = SEEK_SEET , flock.l_start = 0 , flock.l_len = 0
 	2 перейти к началу файла с помощью lseek , потом flock.l_whence = SEEK_CUR , flock.l_start = 0 , flock.l_len = 0
 
 	Чаще всего используется первый метод.
 
На один файл может быть установлено несколько блокировок на чтение , и только одна на запись. Нельзя установить блокировку на чтение для файла , который заблокирован на запись . Рекомендательная блокировка - advisory lock - в соответствии со стандартами POSIX говорит следующее : Если файл заблокирован на чтение , в него можно писать . Если файл заблокирован на запись , из него можно читать .

Некоторые системы предоставляют возможность обязательной блокировки - mandatory locking . для нее требуется выполнение 2-х условий :

       
 	Бит group-execute должен быть снят
 	Бит set-group-ID должен быть установлен
 

Напишем следующую программу , устанавливающую блокировку на чтение для всего файла и порождающую 2 процесса с помощью fork . Первый из них делает блокировку на запись , а второй процесс секунду спустя пытается сделать блокировку на чтение . Временная диаграмма :

       
 //lock/test2
 
 int
 main(int argc, char **argv)
 {
 	int		fd;
 
 	fd = Open("test1.data", O_RDWR | O_CREAT, FILE_MODE);
 
 	Read_lock(fd, 0, SEEK_SET, 0);		/* parent read locks entire file */
 	printf("%s: parent has read lock\n", Gf_time());
 
 	if (Fork() == 0) {
 			/* 4first child */
 		sleep(1);
 		printf("%s: first child tries to obtain write lock\n", Gf_time());
 		Writew_lock(fd, 0, SEEK_SET, 0);	/* this should block */
 		printf("%s: first child obtains write lock\n", Gf_time());
 		sleep(2);
 		Un_lock(fd, 0, SEEK_SET, 0);
 		printf("%s: first child releases write lock\n", Gf_time());
 		exit(0);
 	}
 
 	if (Fork() == 0) {
 			/* 4second child */
 		sleep(3);
 		printf("%s: second child tries to obtain read lock\n", Gf_time());
 		Readw_lock(fd, 0, SEEK_SET, 0);
 		printf("%s: second child obtains read lock\n", Gf_time());
 		sleep(4);
 		Un_lock(fd, 0, SEEK_SET, 0);
 		printf("%s: second child releases read lock\n", Gf_time());
 		exit(0);
 	}
 
 	/* 4parent */
 	sleep(10);
 	Un_lock(fd, 0, SEEK_SET, 0);
 	printf("%s: parent releases read lock\n", Gf_time());
 	exit(0);
 }
 
 
Родительский процесс открывает файл и устанавливает блокировку на чтение на весь файл. При этом мы выводим время получения этой блокировки. Создаем первый процесс , который блокирует файл на запись , снимает эту блокировку и завершается. Создаем второй процесс , который пытается получить блокировку на чтение .
       
 	21:11:43.472154: parent has read lock
 	21:11:44.473772: first child tries to obtain write lock
 	21:11:46.479094: second child tries to obtain read lock
 	21:11:46.479385: second child obtains read lock
 	21:11:50.481361: second child releases read lock
 	21:11:53.477565: first child obtains write lock
 	21:11:53.477605: parent releases read lock
 
Единственная разница со стивенсом - на моей машине пришлось увеличить время ожидания родительского процесса с 5 секунд до 10 .

Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье