■ SEM_NSEMS_MAX — максимальное количество одновременно открытых семафоров для одного процесса (Posix требует, чтобы это значение было не менее 256);
■ SEM_VALUE_MAX — максимальное значение семафора (Posix требует, чтобы оно было не меньше 32767).
Две эти константы обычно определены в заголовочном файле
Пример: программа semsysconf
Программа в листинге 10.20 вызывает sysconf и выводит два ограничения на семафоры, зависящие от конкретной реализации.
//pxsem/semsysconf.с
1 #include "unpipc.h"
2 int
3 main(int argc, char **argv)
4 {
5 printf("SEM_NSEMS_MAX = %ld, SEM_VALUE_MAX = %ld\n",
6 Sysconf(_SC_SEM_NSEMS_MAX), Sysconf(_SC_SEM_VALUE_MAX));
7 exit(0);
8 }
При запуске этой программы в наших двух тестовых системах получим следующий результат:
solaris % semsysconf
SEMS_NSEMS_MAX = 2147483647, SEM_VALUE_MAX = 2147483647
alpha % semsysconf
SEMS_NSEMS_MAX = 256, SEM_VALUE_MAX = 32767
10.14. Реализация с использованием FIFO
Займемся реализацией именованных семафоров Posix с помощью каналов FIFO. Именованный семафор реализуется как канал FIFO с конкретным именем. Неотрицательное количество байтов в канале соответствует текущему значению семафора. Функция sem_post помещает 1 байт в канал, a sem_wait считывает его оттуда (приостанавливая выполнение процесса, если канал пуст, а именно этого мы и хотим). Функция sem_open создает канал FIFO, если указан флаг O_CREAT; открывает его дважды (один раз на запись, другой — на чтение) и при создании нового канала FIFO помещает в него некоторое количество байтов, указанное в качестве начального значения.
ПРИМЕЧАНИЕ
Этот и последующие разделы данной главы содержат усложненный материал, который можно при первом чтении пропустить.
Приведем текст нашего заголовочного файла semaphore.h, определяющего фундаментальный тип sem_t (листинг 10.21).
//my_pxsem_fifo/semaphore.h
1 /* фундаментальный тип */
2 typedef struct {
3 int sem_fd[2]; /* два дескриптора fd: [0] для чтения, [1] для записи */
4 int sem_magic; /* магическое число */
5 } mysem_t;
6 #define SEM_MAGIC 0x89674523
7 #ifdef SEM_FAILED
8 #undef SEM_FAILED
9 #define SEM_FAILED ((mysem_t *)(-1)) /* чтобы компилятор не выдавал предупреждений*/
10 #endif
1-5 Новая структура данных содержит два дескриптора, один из которых предназначен для чтения из FIFO, а другой — для записи. Для единообразия мы храним оба дескриптора в массиве из двух элементов, в котором первый дескриптор всегда открыт на чтение, а второй — на запись.
Поле sem_magiс содержит значение SEM_MAGIC, если структура проинициализирована. Это значение проверяется всеми функциями, которым передается указатель на тип sem_t, чтобы гарантировать, что передан был действительно указатель на заранее инициализированную структуру, а не на произвольную область памяти. При закрытии семафора этому полю присваивается значение 0. Этот метод хотя и не совершенен, но дает возможность обнаружить некоторые ошибки при написании программ.
Функция sem_open
В листинге 10.22 приведен текст функции sem_open, которая создает новый семафор или открывает существующий.
//my_pxsem_fifo/sem_open.с
1 #include "unpipc.h"
2 #include "semaphore.h"
3 #include
4 mysem_t *
5 mysem_open(const char *pathname, int oflag, …)
6 {
7 int i, flags, save_errno;
8 char c;
9 mode_t mode;
10 va_list ap;
11 mysem_t *sem;
12 unsigned int value;
13 if (oflag & O_CREAT) {