Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
      Languages 
      Kernels 
      Packages 
      Books 
      Tests 
      OS 
      Forum 
      Математика 
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...2340 
 Trees...1470 
 William Gropp...1422 
 Ethreal 3...1402 
 Ethreal 4...1384 
 C++ Patterns 3...1383 
 Максвелл 3...1371 
 Httpd-> История Ap...1371 
 Rodriguez 6...1368 
 Go Web ...1365 
 Robert Love 5...1365 
 Максвелл 5...1364 
 OS ->Intel Manual 1...1363 
 Ext4 FS...1362 
 K&R 1...1361 
 Kamran Husain...1360 
 Rubni-Corbet -> Глав...1359 
 Perl OOP...1356 
 Стивенс 9...1355 
 Erlang...1355 
 
  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 .

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

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

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