Семафоры

Семафоры - счетчики, которые разрешают синхронизировать множественные потоки. Linux предлогает альтернативную реализацию семафоров, которые могут использоваться для синхронизации процессов (семафоры процессов или, иногда, System V семафоры). Семафоры процессов выделяются, используются, и освобождаются как и сегменты общей памяти. Хотя одного семафора достаточно для любого использования, семафоры процессов входят в наборы. Мы представляем системные вызовы для семафоров процессов, показывая, как имитировать простой двоичный семафор, используя их.

Выделение и освобождение

Вызовы semget и semctl выделяют и освобождают семафоры, аналогично shmget и shmctl для общей памяти. Вызовите semget с ключом, определяющим набор семафора, число семафоров в наборе, и флажки прав доступа, как и для shmget; возвращаемое значение - идентификатор набора семафора. Вы можете получить идентификатор существующего семафора, зная значение его ключа; в этом случае, число семафоров может быть нулевым.

Семафоры продолжают существовать даже после того, как все процессы, использующие их завершились. Последний процесс, использующий набор семафора, должен явно удалить его. Чтобы это сделать, вызовите semctl с идентификатором семафора, числом семафоров в наборе, IPC_RMID как третий параметр, и любое значение union semun как четвертый параметр (который игнорируется). Эффективный пользовательский идентификатор вызывающего процесса должен соответствовать идентификатору программы выделевшей семафор (или вызывающая программа должна быть запущена суперпользователем). В отличие от сегментов общей памяти, удаление семафора заставляет Linux освобождать его немедленно.

Листинг 5.2 демонстрирует функции выделения и освободения двоичного семафора.
Выделение и освобождение двоичного семафора.(sem_al.c)

	#include <sys/ipc.h>
	#include <sys/sem.h>
	#include <sys/types.h>
	/* Мы должны определить  union semun  самостоятельно.  */ 
	union semun {
		int val;
		struct semid_ds *buf;
		unsigned short int *array;
		struct seminfo *__buf;
	};
	/* Получить идентификатор двоичного семафора, выделяя его в случае  необходимости. */
	int binary_semaphore_allocation (key_t key, int sem_flags)
	{
		return semget (key, 1, sem_flags);
	}
	* Освобождаем двоичной семафор. Все пользователи должны закончить использование семафора 
		к этому моменту.  Возвращает -1 при ошибке. */ 
	int binary_semaphore_deallocate (int semid)
	{
		union semun ignored_argument;
		return semctl (semid, 1, IPC_RMID, ignored_argument);
	}

Ожидание и перенос операции

Каждый семафор имеет неотрицательное значение и поддерживает задержку и перенос операции. Системный вызов semop осуществляет обе операции. Его первый параметр определяет идентификатор набора семафора. Его второй параметр - массив struct sembuf , определяющие операции, которые вы хотите выполнить. Третий параметр - длина этого массива.

Листинг 5.4 демонстрирует ожидание и перенос операции для двоичного семафора. (sem_w.c)

	#include <sys/types.h>
	#include <sys/ipc.h>
	#include <sys/sem.h>
	/* обслужить двойной  семафор. блокировка, пока   значение  семафора  положительное, заетм  декремент на 1. */ 
	int binary_semaphore_wait (int semid)
	{
		struct sembuf operations[1];
		/* использовать первый  (и только) семафор. */ 
		operations[0].sem_num = 0;
		/*  декремент 1. */
		operations[0].sem_op = -1;
		/*  разрешается отмена операции*/
		operations[0].sem_flg = sem_undo;
		return semop (semid, operations, 1);
	}
	/* пост к двоичному  семафору: увеличиваем его значение на 1. это выполнится немедленно. */
	int binary_semaphore_post (int semid)
	{
		struct sembuf operations[1];
		/* используем  первый семафор. */
		operations[0].sem_num = 0;
		/* increment by 1. */
		/* приращение на 1. */
		operations[0].sem_op = 1;
		/*разрешаем отмену операции. */ 
		operations[0].sem_flg = sem_undo;
		return semop (semid, operations, 1);
	}

Определение флажка SEM_UNDO разрешает работать с проблемой завершения процесса при выделении ему ресурсов через семафор. Когда процесс завершается, добровольно или непреднамеренно, значения семафора автоматически корректируются, чтобы "отменить" эффекты процесса на семафор. Например, если процесс, который уменьшил семафор, уничтожен, значение семафора увеличевается.

Отладка семафоров

Используйте команду ipcs -s , чтобы отобразить информацию о существующих наборах семафоров.

Используйте команду ipcrm sem , чтобы удалить набор семафоров из командной строки. Например, чтобы удалить набор семафора с идентификатором 5790517, используйте следующую команду:

% ipcrm sem 5790517