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...766 
 Ext4 FS...755 
 Clickhouse...754 
 Steve Pate 1...754 
 Ethreal 1...742 
 Secure Programming for Li...732 
 C++ Patterns 3...716 
 Ulrich Drepper...698 
 Assembler...695 
 DevFS...662 
 Стивенс 9...650 
 MySQL & PosgreSQL...632 
 
  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);
 }
 
  
 
Оставьте свой комментарий !

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

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