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
 Rodriguez 3...2373 
 Linux Kernel 2.6...1781 
 Trees...1412 
 William Gropp...1409 
 Clickhouse...1409 
 Rodriguez 7...1406 
 Стивенс 9...1406 
 M.Pilgrim->Часть 2...1405 
 Httpd-> История Ap...1404 
 Mod_perl 2...1404 
 OS ->Intel Manual 1...1403 
 Part 3...1403 
 Rodriguez 6...1403 
 Rodriguez 8...1402 
 ground Up...1401 
 Cluster 2...1400 
 FAQ...1400 
 Stewens -> IPC 9...1400 
 Ext4 FS...1400 
 Robert Love 2...1399 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org

Глава 11 , Семафоры System V

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

Семафоры бывают :

       
 	1 Бинарные , т.е. могут приобретать только 2 значения - 1 и 0
 	2 Счетчики , принимающие значения от 0 до некоторого значения
 	3 Набор семафоров-счетчиков ограниченного количества . для каждого такого набора
 		поддерживается структура semid_ds. Каждый элемент этой структуры
 		описывается с помощью другой структуры - sem .
 
Помимо этого , для каждого семафора ядро хранит 3 поля
       
 	1 id последнего процесса ,	изменившего процесс 
 	2 число процессов , ждущих , когда семафор увеличит значение
 	3 число процессов , ждущих , когда семафор обнулится
 
Если в структуре 2 семафора , то она выглядит примерно так :

Функция semget создает набор семафоров либо открывает доступ к уже существующим :

       
 	int semget(key_t key,int nsems,int flag)
 
    Возвращает положительный идентификатор в случае успеха ,
    который в дальнейшем будет использоваться функциями semop и semctl 
    
 	nsems задает число семафоров
 	
 	флаг - на чтение-запись
 	
 
Функция semop позволяет выполнить некоторые действия с созданным семафором .
       
 	int semop(int semid , struct sembuf *ptr , size_t s)
 
 	Указатель ptr указывает на массив структур sembuf
 
Число элементов в массиве sembuf задается 3-м параметром. Каждый элемент этого массива определяет операцию с одним конкретным семафором . sem_num - номер семафора . Каждая операция задается sem_op , которое может быть отрицательным , нулевым или положительным .
       
  struct sem {
 	ushort_t semval ; // значение семафора
 	short sempid;     // pid последнего процесса , вызвавшего semop() , SETVAL , SETALL
 	ushort_t semncnt; // количество ожидающих того , что значение превысит текущее
 	ushort_t semzcnt; // число ожидающих того , что значение семафора станет равным 0  
 	}
 
semop - медленный системный вызов , который прерывается перехватываемыми сигналами . Если семафор во время операции удаляется , semop возвращает ошибку .

В зависимости от того , каким является аргумент sem_op - отрицательным , нулем или положительным - поведение функции semop будет следующее :

       
 	1  Если sem_op > 0 , оно добавляется к semval . Это равносильно освобождению ресурсов , 
 		 захваченных семафором . Если указан флаг SEM_UNDO , значение semop вычитается .
 	2  Если sem_op = 0 , вызвавший поток блокируется до тех пор , пока знвчение semval
 		не станет равным нулю . Если semval = 0 , происходит возвращение из функции . 
 	3 Если sem_op < 0 , поток блокируется , пока semval не станет большим либо равным модулю sem_op.
 		Это равносильно запросу ресурса .
 		Если semval больше либо равно модулю sem_op , sem_op вычитается из semval .
 
Функция semctl выполняет управляющие операции :
       
 	int semctl(int semid , int semnum , int cmd , union semum arg
 
 	Возвращает положительное число в случае успеха
 
Четвертый аргумент - дополнительный , добавляется в зависимости от команды cmd :
       
 	union semun{
 		int val;
 		struct semid_ds *buf;
 		ushort *array;
 		}
 
Его нужно декларировать в приложении . Оно передается по значению . Аргумент cmd может приобретать значения :
       
 	GETVAL 
 	SETVAL 
 	GETPID 
 	GETNCNT 
 	GETZCNT 
 	GETALL 
 	SETALL 
 	IPC_RMID
 	IPC_SET
 	IPC_STAT 
 
Программа semcreate создает набор семафоров - флаг -e соответствует IPC_EXCL при вызове semget :
       
 //svsem/semcreate.c
 
 int
 main(int argc, char **argv)
 {
 	int		c, oflag, semid, nsems;
 
 	oflag = SVSEM_MODE | IPC_CREAT;
 	while ( (c = Getopt(argc, argv, "e")) != -1) {
 		switch (c) {
 		case 'e':
 			oflag |= IPC_EXCL;
 			break;
 		}
 	}
 	if (optind != argc - 2)
 		err_quit("usage: semcreate [ -e ] < pathname> < nsems>");
 	nsems = atoi(argv[optind + 1]);
 
 	semid = Semget(Ftok(argv[optind], 0), nsems, oflag);
 	exit(0);
 }
 	
 
Программа semrmid удаляет набор семафоров , для этого используется semctl с флагом IPC_RMID :
       
 int
 main(int argc, char **argv)
 {
 	int		semid;
 
 	if (argc != 2)
 		err_quit("usage: semrmid < pathname>");
 
 	semid = Semget(Ftok(argv[1], 0), 0, 0);
 	Semctl(semid, 0, IPC_RMID);
 
 	exit(0);
 }
 
 
Программа semsetvalues устанавливает значения семафоров . Вызываются semget , потом semctl с флагом IPC_STAT
       
 	int
 main(int argc, char **argv)
 {
 	int		semid, nsems, i;
 	struct semid_ds	seminfo;
 	unsigned short	*ptr;
 	union semun	arg;
 
 	if (argc < 2)
 		err_quit("usage: semsetvalues < pathname> [ values ... ]");
 
 		/* 4first get the number of semaphores in the set */
 	semid = Semget(Ftok(argv[1], 0), 0, 0);
 	arg.buf = &seminfo;
 	Semctl(semid, 0, IPC_STAT, arg);
 	nsems = arg.buf->sem_nsems;
 
 		/* 4now get the values from the command line */
 	if (argc != nsems + 2)
 		err_quit("%d semaphores in set, %d values specified", nsems, argc-2);
 
 		/* 4allocate memory to hold all the values in the set, and store */
 	ptr = Calloc(nsems, sizeof(unsigned short));
 	arg.array = ptr;
 	for (i = 0; i < nsems; i++)
 		ptr[i] = atoi(argv[i + 2]);
 	Semctl(semid, 0, SETALL, arg);
 
 	exit(0);
 }
 
 
Программа semgetvalues получает значения семафоров :
       
 int
 main(int argc, char **argv)
 {
 	int		semid, nsems, i;
 	struct semid_ds	seminfo;
 	unsigned short	*ptr;
 	union semun	arg;
 
 	if (argc != 2)
 		err_quit("usage: semgetvalues < pathname>");
 
 		/* 4first get the number of semaphores in the set */
 	semid = Semget(Ftok(argv[1], 0), 0, 0);
 	arg.buf = &seminfo;
 	Semctl(semid, 0, IPC_STAT, arg);
 	nsems = arg.buf->sem_nsems;
 
 		/* 4allocate memory to hold all the values in the set */
 	ptr = Calloc(nsems, sizeof(unsigned short));
 	arg.array = ptr;
 
 		/* 4fetch the values and print */
 	Semctl(semid, 0, GETALL, arg);
 	for (i = 0; i < nsems; i++)
 		printf("semval[%d] = %d\n", i, ptr[i]);
 
 	exit(0);
 }
 
 
Программа semops запускается с флагом -n , что соответствует флагу IPC_NOWAIT , параметр -u соответствует флагу SEM_UNDO.
       
 int
 main(int argc, char **argv)
 {
 	int		c, i, flag, semid, nops;
 	struct sembuf	*ptr;
 
 	flag = 0;
 	while ( (c = Getopt(argc, argv, "nu")) != -1) {
 		switch (c) {
 		case 'n':
 			flag |= IPC_NOWAIT;		/* for each operation */
 			break;
 
 		case 'u':
 			flag |= SEM_UNDO;		/* for each operation */
 			break;
 		}
 	}
 	if (argc - optind < 2)			/* argc - optind = #args remaining */
 		err_quit("usage: semops [ -n ] [ -u ]  operation ...");
 
 	semid = Semget(Ftok(argv[optind], 0), 0, 0);
 	optind++;
 	nops = argc - optind;
 
 		/* 4allocate memory to hold operations, store, and perform */
 	ptr = Calloc(nops, sizeof(struct sembuf));
 	for (i = 0; i < nops; i++) {
 		ptr[i].sem_num = i;
 		ptr[i].sem_op = atoi(argv[optind + i]);	/* <0, 0, or >0 */
 		ptr[i].sem_flg = flag;
 	}
 	Semop(semid, ptr, nops);
 
 	exit(0);
 }
 	
 
Теперь запустим цепочку команд :
       
  touch /tmp/rich
  ./semcreate -e /tmp/rich 3
  ./semsetvalues  /tmp/rich 1 2 3
  ./semgetvalues  /tmp/rich
 
 Вывод :
 
 semval[0] = 1
 semval[1] = 2
 semval[2] = 3
 
 Далее выполним :
 
 ./semops -n /tmp/rich 1 2 3
 ./semgetvalues  /tmp/rich
 
 Вывод :
 
 semval[0] = 2
 semval[1] = 4
 semval[2] = 6
 
 
На семафоры System V накладываются ограничения . В следующей таблице в первом столбике - переменная ядра , хранящая ограничение :

Следующая система определяет ограничения для системы :

       
 	int
 main(int argc, char **argv)
 {
 	int		i, j, semid, sid[MAX_NIDS], pipefd[2];
 	int		semmni, semvmx, semmsl, semmns, semopn, semaem, semume, semmnu;
 	pid_t	*child;
 	union semun	arg;
 	struct sembuf	ops[MAX_NOPS];
 
 		/* 4see how many sets with one member we can create */
 	for (i = 0; i <= MAX_NIDS; i++) {
 		sid[i] = semget(IPC_PRIVATE, 1, SVSEM_MODE | IPC_CREAT);
 		if (sid[i] == -1) {
 			semmni = i;
 			printf("%d identifiers open at once\n", semmni);
 			break;
 		}
 	}
 		/* 4before deleting, find maximum value using sid[0] */
 	for (j = 7; j < MAX_VALUE; j += 8) {
 		arg.val = j;
 		if (semctl(sid[0], 0, SETVAL, arg) == -1) {
 			semvmx = j - 8;
 			printf("max semaphore value = %d\n", semvmx);
 			break;
 		}
 	}
 	for (j = 0; j < i; j++)
 		Semctl(sid[j], 0, IPC_RMID);
 
 		/* 4determine max # semaphores per semaphore set */
 	for (i = 1; i <= MAX_MEMBERS; i++) {
 		semid = semget(IPC_PRIVATE, i, SVSEM_MODE | IPC_CREAT);
 		if (semid == -1) {
 			semmsl = i-1;
 			printf("max of %d members per set\n", semmsl);
 			break;
 		}
 		Semctl(semid, 0, IPC_RMID);
 	}
 
 		/* 4find max of total # of semaphores we can create */
 	semmns = 0;
 	for (i = 0; i < semmni; i++) {
 		sid[i] = semget(IPC_PRIVATE, semmsl, SVSEM_MODE | IPC_CREAT);
 		if (sid[i] == -1) {
 /* $$.bp$$ */
 			/*
 			 * Up to this point each set has been created with semmsl
 			 * members.  But this just failed, so try recreating this
 			 * final set with one fewer member per set, until it works.
 			 */
 			for (j = semmsl-1; j > 0; j--) {
 				sid[i] = semget(IPC_PRIVATE, j, SVSEM_MODE | IPC_CREAT);
 				if (sid[i] != -1) {
 					semmns += j;
 					printf("max of %d semaphores\n", semmns);
 					Semctl(sid[i], 0, IPC_RMID);
 					goto done;
 				}
 			}
 			err_quit("j reached 0, semmns = %d", semmns);
 		}
 		semmns += semmsl;
 	}
 	printf("max of %d semaphores\n", semmns);
 done:
 	for (j = 0; j < i; j++)
 		Semctl(sid[j], 0, IPC_RMID);
 
 		/* 4see how many operations per semop() */
 	semid = Semget(IPC_PRIVATE, semmsl, SVSEM_MODE | IPC_CREAT);
 	for (i = 1; i <= MAX_NOPS; i++) {
 		ops[i-1].sem_num = i-1;
 		ops[i-1].sem_op = 1;
 		ops[i-1].sem_flg = 0;
 		if (semop(semid, ops, i)  == -1) {
 			if (errno != E2BIG)
 				err_sys("expected E2BIG from semop");
 			semopn = i-1;
 			printf("max of %d operations per semop()\n", semopn);
 			break;
 		}
 	}
 	Semctl(semid, 0, IPC_RMID);
 
 		/* 4determine the max value of semadj */
 		/* 4create one set with one semaphore */
 	semid = Semget(IPC_PRIVATE, 1, SVSEM_MODE | IPC_CREAT);
 	arg.val = semvmx;
 	Semctl(semid, 0, SETVAL, arg);		/* set value to max */
 	for (i = semvmx-1; i > 0; i--) {
 		ops[0].sem_num = 0;
 		ops[0].sem_op = -i;
 		ops[0].sem_flg = SEM_UNDO;
 		if (semop(semid, ops, 1)  != -1) {
 			semaem = i;
 			printf("max value of adjust-on-exit = %d\n", semaem);
 			break;
 		}
 	}
 	Semctl(semid, 0, IPC_RMID);
 /* $$.bp$$ */
 		/* 4determine max # undo structures */
 		/* 4create one set with one semaphore; init to 0 */
 	semid = Semget(IPC_PRIVATE, 1, SVSEM_MODE | IPC_CREAT);
 	arg.val = 0;
 	Semctl(semid, 0, SETVAL, arg);		/* set semaphore value to 0 */
 	Pipe(pipefd);
 	child = Malloc(MAX_NPROC * sizeof(pid_t));
 	for (i = 0; i < MAX_NPROC; i++) {
 		if ( (child[i] = fork()) == -1) {
 			semmnu = i - 1;
 			printf("fork failed, semmnu at least %d\n", semmnu);
 			break;
 		} else if (child[i] == 0) {
 			ops[0].sem_num = 0;			/* child does the semop() */
 			ops[0].sem_op = 1;
 			ops[0].sem_flg = SEM_UNDO;
 			j = semop(semid, ops, 1);	/* 0 if OK, -1 if error */
 			Write(pipefd[1], &j, sizeof(j));
 			sleep(30);					/* wait to be killed by parent */
 			exit(0);					/* just in case */
 		}
 		/* parent reads result of semop() */
 		Read(pipefd[0], &j, sizeof(j));
 		if (j == -1) {
 			semmnu = i;
 			printf("max # undo structures = %d\n", semmnu);
 			break;
 		}
 	}
 	Semctl(semid, 0, IPC_RMID);
 	for (j = 0; j <= i && child[j] > 0; j++)
 		Kill(child[j], SIGINT);
 
 		/* 4determine max # adjust entries per process */
 		/* 4create one set with max # of semaphores */
 	semid = Semget(IPC_PRIVATE, semmsl, SVSEM_MODE | IPC_CREAT);
 	for (i = 0; i < semmsl; i++) {
 		arg.val = 0;
 		Semctl(semid, i, SETVAL, arg);		/* set semaphore value to 0 */
 
 		ops[i].sem_num = i;
 		ops[i].sem_op = 1;					/* add 1 to the value */
 		ops[i].sem_flg = SEM_UNDO;
 		if (semop(semid, ops, i+1) == -1) {
 			semume = i;
 			printf("max # undo entries per process = %d\n", semume);
 			break;
 		}
 	}
 	Semctl(semid, 0, IPC_RMID);
 
 	exit(0);
 }
 
  
 
Оставьте свой комментарий !

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

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