
- •Часть 4. Локальное взаимодействие процессов
- •Глава 16. Блокирование записей 89
- •12.2. Процессы, потоки и общий доступ к информации
- •12.3. Живучесть объектов ipc
- •12.4. Пространства имен
- •12.5. Действие команд fork, exec и exit на объекты ipc
- •12.6. Комментарии к примерам ipc
- •12.7. Выводы по главе 12
- •12.8. Упражнения по главе 12
- •Глава 13. Именованные и неименованные каналы
- •13.1. Введение
- •13.2. Приложение типа клиент-сервер
- •13.3. Программные каналы
- •13.4. Функции popen и pclose
- •13.5. Именованные каналы (fifo)
- •13.6. Некоторые свойства именованных и неименованных каналов
- •13.7. Один сервер, несколько клиентов
- •13.8. Последовательные и параллельные серверы
- •13.9. Ограничения программных каналов и fifo
- •13.10. Выводы по главе 13
- •13.11. Упражнения по главе 13
- •Глава 14. Программные потоки
- •14.1. Введение
- •14.2. Концепция потоков
- •14.3. Идентификация потоков
- •14.4. Создание потока
- •14.5. Завершение потока
- •Функции управления процессами и потоками
- •14.6. Установка атрибутов потока
- •14.7. Реентерабельность
- •Альтернативные версии функций, безопасные в многопоточной среде
- •14.8. Локальные данные потоков
- •14.9. Принудительное завершение потоков
- •Некоторые точки выхода, определенные стандартом Posix.1
- •14.10. Потоки и сигналы
- •14.11. Выводы по главе 14
- •14.12. Упражнения по главе 14 Глава 15. Средства синхронизации потоков
- •15.1. Введение
- •15.2. Взаимные исключения: установка и снятие блокировки
- •15.2.1. Схема производитель-потребитель
- •15.2.2. Блокирование и опрос
- •15.2.3. Предотвращение тупиковых ситуаций
- •15.3. Условные переменные
- •15.3.1. Ожидание и сигнализация
- •15.3.2. Исключение состояния гонок
- •15.4. Блокировки чтения-записи
- •15.5. Атрибуты средств синхронизации потоков
- •15.5.1. Атрибуты взаимных исключений
- •Поведение взаимных исключений различных типов
- •15.5.2. Атрибуты условных переменных
- •15.5.3. Атрибуты блокировок чтения-записи
- •15.6. Выводы по главе 15
- •15.7. Упражнения по главе 15
- •Глава 16. Блокирование записей
- •16.1. Введение
- •16.2. Блокирование записей и файлов
- •16.3. Блокирование записей с помощью fcntl по стандарту Posix
- •16.4. Рекомендательная блокировка
- •16.5. Обязательная блокировка
- •16.6. Приоритет чтения и записи Выводы по главе 16
- •Упражнения по главе 16 Глава 17. System V ipc
- •17.1. Введение
- •17.2. Ключи типа key_t и функция ftok
- •17.3. Структура ipc_perm
- •17.4. Создание и открытие каналов ipc
- •17.5. Разрешения ipc
- •17.6. Программы ipcs и ipcrm
- •17.7. Ограничения ядра
- •17.8. Выводы по главе 17
- •17.9. Упражнения по главе 17
- •Глава 18. Очереди сообщений System V
- •18.1. Введение
- •18.2. Функция msgget
- •18.3. Функция msgsnd
- •18.4. Функция msgrcv
- •18.5. Функция msgctl
- •18.6. Пример программы клиент-сервер
- •18.7. Мультиплексирование сообщений
- •18.7.1. Пример: одна очередь на приложение
- •18.7.2. Пример: одна очередь для каждого клиента
- •18.8. Ограничения, накладываемые на очереди сообщений
- •18.9. Выводы по главе 18
- •18.10. Упражнения по главе 18
- •Глава 19. Семафоры System V
- •19.1. Введение
- •19.2. Функция semget
- •19.3. Функция semop
- •19.4. Функция semctl
- •19. . Ограничения семафоров System V
- •19. . Выводы по главе 19
- •19. . Упражнения по главе 19 Глава 20. Введение в разделяемую память
- •20.1. Введение
- •20.2. Функции mmap, munmap и msync
- •20.3. Увеличение счетчика в отображаемом в память файле
- •20.4. Неименованное отображение в память
- •20.5. Обращение к объектам, отображенным в память
- •20.6. Выводы по главе 20
- •20.7. Упражнения по главе 20
- •Глава 21. Разделяемая память System V
- •21.1. Введение
- •21.2. Функция shmget
- •21.3. Функция shmat
- •21.4. Функция shmdt
- •21.5. Функция shmctl
- •21.6. Ограничения, накладываемые на разделяемую память
- •21.7. Выводы по главе 21
- •21.8. Упражнения по главе 21
17.2. Ключи типа key_t и функция ftok
В табл. 12.2 было отмечено, что для обращения к объектам System V IPC используются ключи типа key_t. Заголовочный файл <sys/types.h> определяет тип key_t как целое (по меньшей мере 32-разрядное). Значения переменным этого типа обычно присваиваются функцией ftok.
Функция ftok принимает полное имя существующего файла и целочисленный идентификатор, возвращая в качестве результата значение типа key_t (называемое ключом IPC – IPC key):
#include <sys/ipc.h>
key_t ftok (const char *pathname, int id);
/* возвращает ключ IPC либо -1 при возникновении ошибки */
На самом деле функция использует полное имя файла и младшие 8 бит идентификатора для формирования целочисленного ключа IPC.
Эта функция действует в предположении, что для конкретного приложения, использующего IPC, клиент и сервер используют одно и то же полное имя объекта IPC, имеющее какое-то значение в контексте приложения. Это может быть имя демона сервера или имя файла данных, используемого сервером, или имя еще какого-нибудь объекта файловой системы. Если клиенту и серверу для связи требуется только один канал IPC, идентификатору можно присвоить, например, значение 1. Если требуется несколько каналов IPC (например, один от сервера к клиенту и один в обратную сторону), идентификаторы должны иметь разные значения: например, 1 и 2. После того как клиент и сервер договорятся о полном имени и идентификаторе, они оба вызывают функцию ftok для получения одинакового ключа IPC.
Большинство реализаций ftok вызывают функцию stat, а затем объединяют:
информацию о файловой системе, к которой относится полное имя pathname(полеst_devструктурыstat);
номер узла (i-node) в файловой системе (поле st_inoструктурыstat);
младшие 8 бит идентификатора (который не должен равняться нулю).
Из комбинации этих трех значений обычно получается 32-разрядный ключ. Нет никакой гарантии того, что для двух различных путей с одним и тем же идентификатором получатся разные ключи, поскольку количество бит информации в трех перечисленных элементах (идентификатор файловой системы, номер узла, идентификатор IPC) может превышать общее число бит в ключе.
Если указанное полное имя не существует или недоступно вызывающему процессу, ftokвозвращает значение –1. Помните, что файл, имя которого используется для вычисления ключа, не должен быть одним из тех, которые создаются и удаляются сервером в процессе работы, поскольку каждый раз при создании заново эти файлы получают, вообще говоря, другой номер узла, а это может изменить ключ, возвращаемый функциейftokпри очередном вызове.
Пример. Программа влистинге 16.1принимает полное имя файла в качестве аргумента командной строки, вызывает функцииstatиftok, затем выводит значения полейst_devиst_inoструктурыstatи получающийся ключ IPC. Эти три значения выводятся в шестнадцатеричном формате, поэтому легко видеть, как именно формируется ключ IPC из этих двух значений и идентификатора0x57.
Листинг 16.1. Получение и вывод информации о файле и созданном ключе IPC
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char **argv)
{
struct stat mystat;
if (argc != 2)
{
fprintf(stderr, "Использование: ftok <полное_имя_файла>\n");
exit(1);
}
if (stat(argv[1], &mystat) == -1)
{
fprintf(stderr, "Ошибка вызова функции stat: %s\n", strerror(errno));
exit(1);
}
printf("st_dev: %lx, st_ino: %lx, key: %x\n",
(unsigned long) mystat.st_dev,
(unsigned long) mystat.st_ino,
ftok(argv[1], 0x57));
exit(0);
}
Выполнение этой программы в ОС Linux дало следующие результаты:
$ ftok /etc/passwd
st_dev: 301, st_ino: 52aa9, key: 57012aa9
$ ftok /tmp
st_dev: 301, st_ino: 177c1, key: 570177c1
$ ftok /home/sergeant/list
st_dev: 305, st_ino: 139d, key: 5705139d
Очевидно, идентификатор определяет старшие 8 бит ключа; далее в ключ заносятся младшие 8 бит st_devи младшие 16 битst_ino.
Цель этого примера в том, чтобы проиллюстрировать алгоритм комбинирования информации о файле и значения идентификатора для вычисления значения ключа IPC, применяемый в ОС Linux. В других реализациях алгоритм может быть другим.