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
 MINIX...3057 
 Solaris...2933 
 LD...2905 
 Linux Kernel 2.6...2470 
 William Gropp...2182 
 Rodriguez 6...2014 
 C++ Templates 3...1945 
 Trees...1938 
 Kamran Husain...1866 
 Secure Programming for Li...1792 
 Максвелл 5...1710 
 DevFS...1694 
 Part 3...1684 
 Stein-MacEachern-> Час...1632 
 Go Web ...1626 
 Ethreal 4...1619 
 Arrays...1607 
 Стивенс 9...1604 
 Максвелл 1...1592 
 FAQ...1539 
 
  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 .

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

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

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