Ipc linux что это

Обновлено: 04.07.2024

[Linux] Обзор межпроцессного взаимодействия Linux (IPC)

труба

Канал на самом деле является разделом разделяемой памяти, используемой для межпроцессного взаимодействия.Процесс, который создает канал, называется канальным сервером, а процесс, связанный с каналом, является клиентом канала. После того, как один процесс записывает данные в канал, другой процесс может прочитать их с другого конца канала. Трубопровод имеет следующие характеристики:

  • Трубопровод является полудуплексным, и данные могут передаваться только в одном направлении. Когда две стороны должны обмениваться данными, необходимо установить два конвейера;
  • Его можно использовать только между родительскими и дочерними процессами или процессами одного уровня (процессы с родством), например fork или exec Новый процесс создан, используется exec При создании нового процесса необходимо передать файловый дескриптор канала в качестве параметра exec Новый процесс, созданный при использовании родительского процесса fork Когда созданный дочерний процесс обменивается данными напрямую, процесс, отправляющий данные, закрывает конец чтения, а процесс, получающий данные, закрывает конец записи;
  • Отдельно составляют независимую файловую систему: конвейер - это файл для процессов на обоих концах конвейера, но это не обычный файл, он не принадлежит определенной файловой системе, а самоподдерживающийся портал, который составляет только файловую систему, и Существует только в памяти;
  • Чтение и запись данных. Содержимое, записанное процессом в конвейер, считывается процессом на другом конце конвейера, и записанное содержимое добавляется в конец буфера конвейера каждый раз и каждый раз из заголовка буфера. Часть зачитала данные.

Механизм реализации трубопровода

Канал - это буфер, управляемый ядром, который эквивалентен листу бумаги, который мы поместили в память. Один конец трубы подключен к выходу процесса. Этот процесс поместит информацию в конвейер. Другой конец канала связан с входом процесса, и этот процесс извлекает информацию, которая была помещена в канал. Буфер не должен быть большим, он спроектирован как кольцевая структура данных, чтобы конвейер можно было использовать повторно. Когда в канале нет информации, процесс, считывающий канал, будет ждать, пока процесс на другом конце не поместит информацию. Когда канал заполнен информацией, процесс, пытающийся поместить информацию, будет ждать, пока процесс на другом конце не получит информацию. Когда оба процесса завершаются, конвейер автоматически исчезает.

Трубы могут использоваться только на локальном компьютере, а не для связи между сетями.

Пример кода

В следующем примере кода кода реализуется связь между родительским процессом и дочерним процессом:

Используя базовый read с участием write Позвоните, чтобы получить доступ к данным. в fd[1] Записать данные из fd[0] При чтении данных принцип порядка записи и чтения - сначала в порядке, а в порядке.

Правила чтения и записи в конвейере

Когда нет данных для чтения:

  • Если вы отключите дескриптор файла чтения конца канала O_NONBLOCK , Вызов чтения заблокирован, то есть процесс приостанавливает выполнение и ожидает поступления данных;
  • Если вы включите дескриптор файла конца чтения для канала O_NONBLOCK , Вызов read возвращает -1, а значение errno равно EAGAIN;

Когда труба заполнена

  • Если вы отключите дескриптор файла конца записи для канала O_NONBLOCK , Вызов записи блокируется до тех пор, пока процесс не прочитает данные;
  • Если вы включите дескриптор файла конца записи для канала O_NONBLOCK , Вызов возвращает -1, а значение errno равно EAGAIN;

Если все файловые дескрипторы, соответствующие концу записи канала, закрыты, read возвращает 0;

Именованная труба

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

Есть два способа создания именованных каналов:

DESCRIPTION:
mkfifo() creates a new fifo file with name path. The access permissions are specified by mode and restricted by the umask(2) of the calling process.The fifo’s owner ID is set to the process’s effective user ID. The fifo’s group ID is set to that of the parent directory in which it is created.
RETURN VALUES:
A 0 return value indicates success. A -1 return value indicates an error, and an error code is stored in errno.

DESCRIPTION:
The device special file path is created with the major and minor device numbers extracted from mode. The access permissions of path are constrained by the umask(2) of the parent process.If mode indicates a block or character special file, dev is a configuration-dependent specification of a character or block I/O device and the superblock of the device. If mode does not indicate a block special or character special device, dev is ignored. mknod() requires super-user privileges.
RETURN VALUES:
Upon successful completion, a value of 0 is returned. Otherwise, a value of -1 is returned and errno is set to indicate the error.

Разница между трубами и именованными трубами

Для именованного канала FIFO операция ввода-вывода в основном аналогична операции ввода-вывода обычного канала, но между ними есть одно основное отличие: в именованном канале канал можно создать заранее, например, мы выполняем его в командной строке:

Чтобы создать именованный канал, мы должны использовать функцию open, чтобы явно установить канал, связанный с конвейером, и в конвейере конвейер был создан в основном процессе, а затем напрямую скопировать соответствующие данные при форке или создать его с помощью exec В новом процессе файловый дескриптор канала передается как параметр.

Вообще говоря, FIFO всегда находится в заблокированном состоянии, как PIPE. То есть, если разрешение на чтение установлено при открытии именованного канала FIFO, процесс чтения будет заблокирован, пока другие процессы не откроют FIFO и не запишут данные в канал. Это блокирующее действие также верно в обратном порядке. Если вы не хотите блокировать во время операций с именованным каналом, вы можете использовать флаг O_NONBLOCK при открытии, чтобы отключить операцию блокировки по умолчанию.

сигнал

Сигнальный механизм - это самый старый механизм связи между процессами в Unix-системе, используемый для передачи асинхронных сигналов между одним или несколькими процессами. Сигналы могут генерироваться различными асинхронными событиями, такими как прерывания клавиатуры. Оболочка также может использовать сигналы для передачи команд управления заданиями своим дочерним процессам.

В Linux вы можете использовать signal или sigaction для установки функции обработки сигнала для определенного сигнала. Когда процесс получает сигнал, он выполняет функцию обработки сигнала:

Определение sigaction заключается в следующем:

Вы можете отправлять сигналы процессу следующими способами:

Параметр msgp имеет следующую структуру:

Размер массива mtext в структуре задается параметром msgsz.

Структура msqid_ds определяется следующим образом:

сигнал

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

Семафор является специальной переменной, он принимает только положительное целочисленное значение и допускает только две операции с этим значением: wait (ожидание) и signal (сигнал). (P, V операция, P для ожидания, V для сигнала):

  • Если значение sv больше 0, оно вычитается на 1, а если его значение равно 0, выполнение процесса приостанавливается.
  • Если есть другие процессы, которые приостановлены из-за ожидания sv, дайте ему возобновиться, если другие процессы не приостановлены из-за ожидания sv, добавьте 1 к нему

Простое понимание состоит в том, что P эквивалентно заявке на ресурсы, а V эквивалентно освобождению ресурсов.

Вы можете создать семафор через semget:

Измените значение семафора с помощью semop:

Вы можете выполнять операции управления семейством семафоров через semctl:

Общая память

Общая память - это метод межпроцессного взаимодействия, который разделяет область памяти между несколькими процессами. Специальный диапазон адресов, созданный IPC для процесса, появится в адресном пространстве процесса (где здесь адресное пространство? ?)в. Другие процессы могут подключать ту же общую память к своему собственному адресному пространству. Все процессы могут обращаться к адресам в общей памяти, как если бы они были распределены malloc. Если процесс записывает данные в разделяемую память, изменения сразу же будут видны другим процессам.

noteСама разделяемая память не имеет механизма синхронизации и должна контролироваться программистом.

Определение функции общей памяти:

Разница между XSI IPC и PIPE, FIFO

Карта памяти

Файл с отображением в памяти - это отображение из файла в блок памяти. Файлы с отображенной памятью чем-то похожи на виртуальную память. С помощью файлов с отображенной памятью область адреса может быть зарезервирована, и физическое хранилище отправляется в эту область. Физическая память, отображаемая файлом памяти, поступает из файла, который уже существует на диске. Файл должен быть сопоставлен перед продолжением. При использовании отображенных в память файлов для обработки файлов, хранящихся на диске, нет необходимости выполнять операции ввода-вывода с файлами. Каждый процесс, использующий этот механизм, реализует связь между несколькими процессами, отображая один и тот же общий файл в свое собственное адресное пространство процесса (это похоже на общую память, если один процесс работает с памятью этого отображенного файла, Другие процессы также можно увидеть сразу).

Использование отображенных в память файлов может не только обеспечить связь между несколькими процессами, но также может использоваться для обработки больших файлов для повышения эффективности. Поскольку наша общая практика заключается в копировании файлов на диске в буфер в пространстве ядра, а затем в пользовательское пространство (память). После того, как пользователь изменяет данные, данные копируются в буфер и затем копируются в файл на диске, всего четыре копии. , Если объем данных файла велик, стоимость копирования очень велика. Таким образом, вопрос в том, система не должна копировать данные, когда она делает файлы отображения памяти? mmap () не копирует данные. Реальное копирование выполняется во время обработки прерывания сбоя страницы. Так как mmap () напрямую отображает файл в пространство пользователя, функция обработки прерывания напрямую копирует файл с жесткого диска в соответствии с этим отношением сопоставления. Для пользовательского пространства, поэтому только одна копия данных. Эффективность выше, чем чтение / запись.

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

Разница между разделяемой памятью и отображенными в память файлами

  • Отображаемые в память файлы используют виртуальную память для сопоставления файлов с адресным пространством процесса, после чего процесс манипулирует файлом так же, как адрес в пространстве процесса, например, используя функции манипулирования памятью, такие как memcpy на языке c. Этот метод может быть хорошо применен в тех случаях, когда необходимо часто обрабатывать файл или большой файл.Этот метод более эффективен, чем обычный ввод-вывод.
  • Общая память - это особый случай отображаемых в память файлов. Отображаемая память - это блок памяти, а не файл на диске. Предмет общей памяти - «Процесс». По умолчанию операционная система выделяет пространство памяти для каждого процесса. Каждому процессу разрешен только доступ к памяти, выделенной ему операционной системой, и он не может получить доступ к другим процессам. Но иногда необходимо обращаться к одному и тому же разделу памяти между разными процессами, что нам делать? Операционная система предоставляет API для создания доступа к общей памяти. Процессы, которым требуется общая память, могут обращаться к общей памяти между несколькими процессами через этот набор определенных API. Каждый процесс, обращающийся к этой памяти, подобен обращению к жесткому диску. Тот же файл

Разница и связь между отображенным в память файлом и виртуальной памятью

Файлы с отображенной памятью и виртуальная память являются важными частями управления памятью операционной системы, и они имеют сходства и различия.

  • Соединение: Виртуальная память и отображение памяти - это механизм, который загружает часть содержимого в память, а другую - на диск. Это прозрачно для пользователей.
  • Разница: виртуальная память является частью жесткого диска и является областью обмена данными между памятью и жестким диском. Многие программы помещают временно неиспользуемые программные данные в эту виртуальную память во время работы многих программ для экономии ресурсов памяти. Отображение памяти - это сопоставление файла с блоком памяти, чтобы программа могла обращаться к файлу через указатель памяти. Аппаратной основой виртуальной памяти является механизм подкачки. Другим основанием является принцип локальности (временная локальность и пространственная локальность), так что часть программы может быть загружена в память, а остальная часть может быть оставлена ​​во внешней памяти.Если информации о доступе не существует, необходимые данные передаются в память. Отображенный в память файл не является локальным, но область виртуального адресного пространства отображается на весь диск или его часть, и доступ к файлу сопоставленного диска осуществляется через эту область без файлового ввода-вывода или файлового ввода-вывода. Содержание буферизировано.

Разъем

Механизм сокетов может не только взаимодействовать с различными процессами на одном компьютере, но также позволяет взаимодействовать процессам между компьютерами в сети. Создание и использование сокетов отличаются от конвейеров: сокеты четко отличают клиента от сервера, что позволяет нескольким клиентам подключаться к одному серверу.

Как показано на рисунке ниже, уровень сокетов расположен между прикладным уровнем и транспортным уровнем. В операционной системе реализован следующий уровень сокетов:



Сокет - это уровень абстракции промежуточного программного обеспечения для связи между прикладным уровнем и набором протоколов TCP / IP. Это набор интерфейсов. В режиме конструктора Socket фактически является фасадным режимом, который скрывает сложное семейство протоколов TCP / IP за интерфейсом Socket.Для пользователей имеется набор простых интерфейсов, позволяющих Socket организовывать данные в соответствии с указанным протокол. Следовательно, нам не нужно глубоко понимать протокол tcp / udp, сокет был инкапсулирован для нас, нам нужно только следовать правилам сокета для программирования, и программа, написанная естественным образом, следует стандарту tcp / udp.

На следующем рисунке показан процесс связи между сервером и клиентом при программировании сокетов:



Сначала серверное приложение создает сокет с сокетом, который представляет собой ресурс, похожий на файловый дескриптор, выделенный системой для процесса сервера. Далее сервер вызывает bind для именования сокета. Имя - это идентификатор, который позволяет Linux передавать входящие соединения для определенного порта на правильный процесс сервера. Затем система вызывает функцию прослушивания, чтобы начать прослушивание, ожидая подключения клиента. listen создает очередь и использует ее для хранения входящих соединений от клиентов. Когда клиент вызывает connect для запроса соединения, сервер вызывает accept, чтобы принять клиентское соединение, и accept создает новый сокет для связи с этим клиентом. Сначала клиент вызывает сокет для создания безымянного сокета, а затем использует именованный сокет сервера в качестве адреса для вызова соединения для установления соединения с сервером. До тех пор, пока соединение между двумя сторонами установлено успешно, мы можем использовать сокет сокета для достижения связи, подобной базовому файлу.

Соответствующая диаграмма перехода состояний TCP выглядит следующим образом:

Отступление: данная статья является учебной и расчитана на людей, только еще вступающих на путь системного программирования. Ее главный замысел — познакомиться с различными способами взаимодействия между процессами на POSIX-совместимой ОС.

Именованный канал

Примечание: mode используется в сочетании с текущим значением umask следующим образом: (mode &

umask). Результатом этой операции и будет новое значение umask для создаваемого нами файла. По этой причине мы используем 0777 (S_IRWXO | S_IRWXG | S_IRWXU), чтобы не затирать ни один бит текущей маски.

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

В случае успешного создания FIFO файла, mkfifo() возвращает 0 (нуль). В случае каких либо ошибок, функция возвращает -1 и выставляет код ошибки в переменную errno.

  • EACCES — нет прав на запуск (execute) в одной из директорий в пути pathname
  • EEXIST — файл pathname уже существует, даже если файл — символическая ссылка
  • ENOENT — не существует какой-либо директории, упомянутой в pathname, либо является битой ссылкой
  • ENOSPC — нет места для создания нового файла
  • ENOTDIR — одна из директорий, упомянутых в pathname, на самом деле не является таковой
  • EROFS — попытка создать FIFO файл на файловой системе «только-на-чтение»

Пример

mkfifo.c

Мы открываем файл только для чтения (O_RDONLY). И могли бы использовать O_NONBLOCK модификатор, предназначенный специально для FIFO файлов, чтобы не ждать когда с другой стороны файл откроют для записи. Но в приведенном коде такой способ неудобен.

Компилируем программу, затем запускаем ее:

В соседнем терминальном окне выполняем:

В результате мы увидим следующий вывод от программы:

Разделяемая память


Следующий тип межпроцессного взаимодействия — разделяемая память (shared memory). Схематично изобразим ее как некую именованную область в памяти, к которой обращаются одновременно два процесса:

Для выделения разделяемой памяти будем использовать POSIX функцию shm_open():

Функция возвращает файловый дескриптор, который связан с объектом памяти. Этот дескриптор в дальнейшем можно использовать другими функциями (к примеру, mmap() или mprotect()).

Целостность объекта памяти сохраняется, включая все данные связанные с ним, до тех пор пока объект не отсоединен/удален (shm_unlink()). Это означает, что любой процесс может получить доступ к нашему объекту памяти (если он знает его имя) до тех пор, пока явно в одном из процессов мы не вызовем shm_unlink().

  • O_RDONLY — открыть только с правами на чтение
  • O_RDWR — открыть с правами на чтение и запись
  • O_CREAT — если объект уже существует, то от флага никакого эффекта. Иначе, объект создается и для него выставляются права доступа в соответствии с mode.
  • O_EXCL — установка этого флага в сочетании с O_CREATE приведет к возврату функцией shm_open ошибки, если сегмент общей памяти уже существует.

После создания общего объекта памяти, мы задаем размер разделяемой памяти вызовом ftruncate(). На входе у функции файловый дескриптор нашего объекта и необходимый нам размер.

Пример

Следующий код демонстрирует создание, изменение и удаление разделяемой памяти. Так же показывается как после создания разделяемой памяти, программа выходит, но при следующем же запуске мы можем получить к ней доступ, пока не выполнен shm_unlink().

shm_open.c

После создания объекта памяти мы установили нужный нам размер shared memory вызовом ftruncate(). Затем мы получили доступ к разделяемой памяти при помощи mmap(). (Вообще говоря, даже с помощью самого вызова mmap() можно создать разделяемую память. Но отличие вызова shm_open() в том, что память будет оставаться выделенной до момента удаления или перезагрузки компьютера.)

Компилировать код на этот раз нужно с опцией -lrt:

Смотрим что получилось:

Аргумент «create» в нашей программе мы используем как для создания разделенной памяти, так и для изменения ее содержимого.

Зная имя объекта памяти, мы можем менять содержимое разделяемой памяти. Но стоит нам вызвать shm_unlink(), как память перестает быть нам доступна и shm_open() без параметра O_CREATE возвращает ошибку «No such file or directory».

Семафор

Семафор — самый часто употребляемый метод для синхронизации потоков и для контролирования одновременного доступа множеством потоков/процессов к общей памяти (к примеру, глобальной переменной). Взаимодействие между процессами в случае с семафорами заключается в том, что процессы работают с одним и тем же набором данных и корректируют свое поведение в зависимости от этих данных.

  1. семафор со счетчиком (counting semaphore), определяющий лимит ресурсов для процессов, получающих доступ к ним
  2. бинарный семафор (binary semaphore), имеющий два состояния «0» или «1» (чаще: «занят» или «не занят»)

Семафор со счетчиком

Смысл семафора со счетчиком в том, чтобы дать доступ к какому-то ресурсу только определенному количеству процессов. Остальные будут ждать в очереди, когда ресурс освободится.

Итак, для реализации семафоров будем использовать POSIX функцию sem_open():

В функцию для создания семафора мы передаем имя семафора, построенное по определенным правилам и управляющие флаги. Таким образом у нас получится именованный семафор.
Имя семафора строится следующим образом: в начале идет символ "/" (косая черта), а следом латинские символы. Символ «косая черта» при этом больше не должен применяться. Длина имени семафора может быть вплоть до 251 знака.

Если нам необходимо создать семафор, то передается управляющий флаг O_CREATE. Чтобы начать использовать уже существующий семафор, то oflag равняется нулю. Если вместе с флагом O_CREATE передать флаг O_EXCL, то функция sem_open() вернет ошибку, в случае если семафор с указанным именем уже существует.

Параметр mode задает права доступа таким же образом, как это объяснено в предыдущих главах. А переменной value инициализируется начальное значение семафора. Оба параметра mode и value игнорируются в случае, когда семафор с указанным именем уже существует, а sem_open() вызван вместе с флагом O_CREATE.

Для быстрого открытия существующего семафора используем конструкцию:
, где указываются только имя семафора и управляющий флаг.

Пример семафора со счетчиком

Рассмотрим пример использования семафора для синхронизации процессов. В нашем примере один процесс увеличивает значение семафора и ждет, когда второй сбросит его, чтобы продолжить дальнейшее выполнение.

sem_open.c

В одной консоли запускаем:

В соседней консоли запускаем:

Бинарный семафор

Вместо бинарного семафора, для которого так же используется функция sem_open, я рассмотрю гораздо чаще употребляемый семафор, называемый «мьютекс» (mutex).

Мьютекс по существу является тем же самым, чем является бинарный семафор (т.е. семафор с двумя состояниями: «занят» и «не занят»). Но термин «mutex» чаще используется чтобы описать схему, которая предохраняет два процесса от одновременного использования общих данных/переменных. В то время как термин «бинарный семафор» чаще употребляется для описания конструкции, которая ограничивает доступ к одному ресурсу. То есть бинарный семафор используют там, где один процесс «занимает» семафор, а другой его «освобождает». В то время как мьютекс освобождается тем же процессом/потоком, который занял его.

Без мьютекса не обойтись в написании, к примеру базы данных, к которой доступ могут иметь множество клиентов.

Для использования мьютекса необходимо вызвать функцию pthread_mutex_init():

Функция инициализирует мьютекс (перемнную mutex) аттрибутом mutexattr. Если mutexattr равен NULL, то мьютекс инициализируется значением по умолчанию. В случае успешного выполнения функции (код возрата 0), мьютекс считается инициализированным и «свободным».

  • EAGAIN — недостаточно необходимых ресурсов (кроме памяти) для инициализации мьютекса
  • ENOMEM — недостаточно памяти
  • EPERM — нет прав для выполнения операции
  • EBUSY — попытка инициализировать мьютекс, который уже был инициализирован, но не унечтожен
  • EINVAL — значение mutexattr не валидно

Функция pthread_mutex_lock(), если mutex еще не занят, то занимает его, становится его обладателем и сразу же выходит. Если мьютекс занят, то блокирует дальнейшее выполнение процесса и ждет освобождения мьютекса.
Функция pthread_mutex_trylock() идентична по поведению функции pthread_mutex_lock(), с одним исключением — она не блокирует процесс, если mutex занят, а возвращает EBUSY код.
Фунция pthread_mutex_unlock() освобождает занятый мьютекс.

  • EINVAL — mutex неправильно инициализирован
  • EDEADLK — мьютекс уже занят текущим процессом
  • EBUSY — мьютекс уже занят
  • EINVAL — мьютекс неправильно инициализирован
  • EINVAL — мьютекс неправильно инициализирован
  • EPERM — вызывающий процесс не является обладателем мьютекса

Пример mutex

mutex.c

Данный пример демонстрирует совместный доступ двух потоков к общей переменной. Один поток (первый поток) в автоматическом режиме постоянно увеличивает переменную counter на единицу, при этом занимая эту переменную на целую секунду. Этот первый поток дает второму доступ к переменной count только на 10 миллисекунд, затем снова занимает ее на секунду. Во втором потоке предлагается ввести новое значение для переменной с терминала.

Если бы мы не использовали технологию «мьютекс», то какое значение было бы в глобальной переменной, при одновременном доступе двух потоков, нам не известно. Так же во время запуска становится очевидна разница между pthread_mutex_lock() и pthread_mutex_trylock().

Компилировать код нужно с дополнительным параметром -lpthread:

Запускаем и меняем значение переменной просто вводя новое значение в терминальном окне:

Вместо заключения

В следующих статьях я хочу рассмотреть технологии d-bus и RPC. Если есть интерес, дайте знать.
Спасибо.

UPD: Обновил 3-ю главу про семафоры. Добавил подглаву про мьютекс.

Следующие функции используются исключительно для поддержки механизма семафоров:

newary()

newary() обращается к ipc_alloc() для распределения памяти под новый набор семафоров. Она распределяет объем памяти достаточный для размещения дескриптора набора и всего набора семафоров. Распределенная память очищается и адрес первого элемента набора семафоров передается в ipc_addid(). Функция ipc_addid() резервирует память под массив элементов нового набора семафоров и инициализирует ( struct kern_ipc_perm) набор. Глобальная переменная used_sems увеличивается на количество семафоров в новом наборе и на этом инициализация данных ( struct kern_ipc_perm) для нового набора завершается. Дополнительно выполняются следующие действия:

  • В поле sem_base заносится адрес первого семафора в наборе.
  • Очередь sem_pending объявляетяс пустой.

Все операции, следующие за вызовом ipc_addid(), выполняются под глобальной блокировкой семафоров. После снятия блокировки вызывается ipc_buildid() (через sem_buildid()). Эта функция создает уникальный ID (используя индекс дескриптора набора семафоров), который и возвращается в вызывающую программу.

freeary()

Функция freeary() вызывается из semctl_down() для выполнения действий, перечисленных ниже. Вызов функции осуществляется под глобальной блокировкой семафоров, возврат управления происходит со снятой блокировкой.

  • Вызывается ipc_rmid() (через "обертку" sem_rmid()), чтобы удалить ID набора семафоров и получить указатель на набор семафоров.
  • Аннулируется список откатов для данного набора семафоров
  • Все ожидающие процессы пробуждаются, чтобы получить код ошибки EIDRM.
  • Общее количество семафоров уменьшается на количество семафоров в удаляемом наборе.
  • Память, занимаемая набором семафоров, освобождается.

semctl_down()

Функция semctl_down() предназначена для выполнения операций IPC_RMID и IPC_SET системного вызова semctl(). Перед выполнением этих операций проверяется ID набора семафоров и права доступа. Обе эти операции выполняются под глобальной блокировкой семафоров.

IPC_RMID

Операция IPC_RMID вызывает freeary() для удаления набора семафоров.

IPC_SET

Операция IPC_SET изменяет элементы uid , gid , mode и ctime в наборе семафоров.

semctl_nolock()

Функция semctl_nolock() вызывается из sys_semctl() для выполнения операций IPC_INFO, SEM_INFO и SEM_STAT.

IPC_INFO и SEM_INFO

Операции IPC_INFO и SEM_INFO заполняют временный буфер seminfo статическими данными. Затем под глобальной блокировкой семафора ядра sem_ids.sem заполняются элементы semusz и semaem структуры seminfo в соответствии с требуемой операцией (IPC_INFO или SEM_INFO) и в качестве результата возвращается максимальный ID.

SEM_STAT

Операция SEM_STAT инициализирует временный буфер semid64_ds. На время копирования значений sem_otime , sem_ctime , и sem_nsems в буфер выполняется глобальная блокировка семафора. И затем данные копируются в пространство пользователя.

semctl_main()

Функция semctl_main() вызывается из sys_semctl() для выполнения ряда операций, которые описаны ниже. Перед выполнением операций, semctl_main() блокирует семафор и проверяет ID набора семафоров и права доступа. Перед возвратом блокировка снимается.

GETALL

Операция GETALL загружает текущие значения семафора во временный буфер ядра и затем копирует его в пространство пользователя. При небольшом объеме данных, временный буфер размещается на стеке, иначе блокировка временно сбрасывается, чтобы распределить в памяти буфер большего размера. Копирование во временный буфер производится под блокировкой.

SETALL

Операция SETALL копирует значения семафора из пользовательского пространства во временный буфер и затем в набор семафоров. На время копирования из пользовательского пространства во временный буфер и на время проверки значений блокировка сбрасывается. При небольшом объеме данных, временный буфер размещается на стеке, иначе в памяти размещается буфер большего размера. На время выполнения следующих действий блокировка восстанавливается:

  • Информация копируется в набор семафоров.
  • Очищается очередь откатов для заданного набора семафоров.
  • Устанавливается значение sem_ctime для набора семафоров.
  • Вызывается функция update_queue() , которая проходит по списку ожидающих операций в поисках задач, которые могут быть завершены в результате выполнения операции SETALL. Будятся любые ожидающие задачи, которые больше не нужно блокировать.

IPC_STAT

Операция IPC_STAT копирует значения sem_otime , sem_ctime и sem_nsems во временный буфер на стеке. После снятия блокировки данные копируются в пользовательское пространство.

GETVAL

Операция GETVAL возвращает значение заданного семафора.

GETPID

Операция GETPID возвращает pid последней операции, выполненной над семафором.

GETNCNT

Операция GETNCNT возвращает число процессов, ожидающих на семафоре, когда тот станет меньше нуля. Это число подсчитывается функцией count_semncnt().

GETZCNT

Операция GETZCNT возвращает число процессов, ожидающих на семафоре, когда тот станет равным нулю. Это число подсчитывается функцией count_semzcnt().

SETVAL

Проверяет новое значение семафора и выполняет следующие действия:

  • В очереди отката отыскиваются любые корректировки данного семафора и эти корректировки сбрасываются в ноль.
  • Значение семафора устанавливается в заданное.
  • Корректируется значение sem_ctime .
  • Вызывается функция update_queue(), которая проходит по очереди ожидающих операций в поисках тех из них, которые могут быть завершены в результате выполнения операции SETVAL. Все задачи которые оказываются больше незаблокированными - пробуждаются.

count_semncnt()

count_semncnt() возвращает число процессов, ожидающих на семафоре, когда тот станет меньше нуля.

count_semzcnt()

count_semzcnt() возвращает число процессов, ожидающих на семафоре, когда тот станет равным нулю.

update_queue()

update_queue() проходит по очереди ожидающих операций заданного набора семафоров и вызывает try_atomic_semop() для каждой последовательности операций. Если статус элемента очереди показывает, что заблокированная задача уже была разбужена, то такой элемент пропускается. В качестве аргумента do_undo в функцию try_atomic_semop() передается флаг q-alter , который указывает на то, что любые изменяющие операции необходимо "откатить" перед возвратом управления.

Если последовательность операций заблокирована, то update_queue() возвращает управление без внесения каких-либо изменений.

Последовательность операций может потерпеть неудачу, если в результате какой либо из них семафор примет недопустимое значение или если операция имеющая флаг IPC_NOWAIT не может быть завершена. В таком случае задача, ожидающая выполнения заданной последовательности операций, активируется а в поле статуса очереди заносится соответствующий код ошибки и элемент удаляется из очереди.

Если последовательность операций не предполагает внесения изменений, то в качестве аргумента do_undo в функцию try_atomic_semop() передается ноль. Если выполнение этих операций увенчалось успехом, то они считаются выполненными и удаляются из очереди. Ожидающая задача активируется, а в поле status ей передается признак успешного завершения операций.

Если последовательность операций, которая предполагает внесение изменений в значение семафоров, признана успешной, то статус очереди принимает значение 1, чтобы активировать задачу. Последовательность операций не выполняется и не удаляется из очереди, она будет выполняться разбуженной задачей.

try_atomic_semop()

Функция try_atomic_semop() вызывается из sys_semop() и update_queue() и пытается выполнить каждую из операций в последовательности.

Если была встречена заблокированная операция, то процесс исполнения последовательности прерывается и все операции "откатываются". Если последовательность имела флаг IPC_NOWAIT, то возвращается код ошибки -EAGAIN. Иначе возвращается 1 для индикации того, что последовательность операций заблокирована.

Если значение семафора вышло за рамки системных ограничений, то выполняется "откат" всех операций и возвращается код ошибки -ERANGE.

Если последовательность операций была успешно выполнена и при этом аргумент do_undo не равен нулю, то выполняется "откат" всех операций и возвращается 0. Если аргумент do_undo равен нулю, то результат операций остается в силе и обновляется поле sem_otime .

sem_revalidate()

Функция sem_revalidate() вызывается, когда глобальная блокировка семафора временно была снята и необходимо снова ее получить. Вызывается из semctl_main() и alloc_undo(). Производит проверку ID семафора и права доступа, в случае успеха выполняет глобальную блокировку семафора.

freeundos()

Функция freeundos() проходит по списку "откатов" процесса в поисках заданной структуры. Если таковая найдена, то она изымается из списка и память, занимаемая ею, освобождается. В качестве результата возвращается указатель на следующую структуру "отката"в списке.

alloc_undo()

Вызов функции alloc_undo() должен производиться под установленной глобальной блокировкой семафора. В случае возникновения ошибки - функция завершает работу со снятой блокировкой.

Перед тем как вызовом kmalloc() распределить память под структуру sem_undo и массив корректировок, блокировка снимается. Если память была успешно выделена, то она восстанавливается вызовом sem_revalidate().

Далее новая структура инициализируется, указатель на структуру размещается по адресу, указанному вызывающей программой, после чего структура вставляется в начало списка "откатов" текущего процесса.

sem_exit()

Функция sem_exit() вызывается из do_exit() и отвечает за выполнение всех "откатов" по завершении процесса.

Если процесс находится в состоянии ожидания на семафоре, то он удаляется из списка sem_queue при заблокированном семафоре.

Производится просмотр списка "откатов" текущего процесса и для каждого элемента списка выполняются следующие действия:

  • Проверяется структура "отката" и ID набора семафоров.
  • В списке "откатов" соответствующего набора семафоров отыскиваются ссылки на структуры, которые удаляются из списка.
  • К набору семафоров применяются корректировки из структуры "отката".
  • Обновляется поле sem_otime в наборе семафоров.
  • Вызывается update_queue(), которая просматривает список отложенных операций и активирует задачи, которые могут быть разблокированы в результате "отката".
  • Память, занимаемая структурой, освобождается.

По окончании обработки списка очищается поле current->semundo.

Интерфейс системных вызовов

sys_msgget()

sys_msgctl()

IPC_INFO ( или MSG_INFO)

IPC_STAT ( или MSG_STAT)

IPC_SET

IPC_RMID

sys_msgsnd()

sys_msgrcv()

[Подробное использование команды Linux ipcs и команды ipcrm]

1. Знание об общей памяти

Во-вторых, принцип общей памяти

Общая память System V помещает все общие данные в область общей памяти. Любой процесс, который хочет получить доступ к данным, должен добавить область памяти в адресное пространство процесса, чтобы отобразить страницу физической памяти, в которой хранятся общие данные. Совместно используемая память System V получает или создает область разделяемой памяти IPC через функцию shmget и возвращает соответствующий идентификатор. Ядро гарантирует, что shmget получает или создает область совместно используемой памяти, инициализирует соответствующую структуру shmid_kernel в области совместно используемой памяти, а также будет находиться в специальной Файл с тем же именем создается и открывается в файловой системе shm, а соответствующие структуры dentry и inode файла устанавливаются в памяти. Вновь открытый файл не принадлежит ни одному процессу. Все это выполняется системой, вызывающей функцию shmget.

Три, файл конфигурации sysctl.conf

Вышеупомянутые два параграфа объяснения - содержание понимания, найденного в Интернете. Как сопровождающий системы Linux, параметры, относящиеся к общей памяти, находятся в основном в нескольких элементах конфигурации в /etc/sysctl.conf. детали следующим образом:

  1. kernel.shmmax = 4398046511104
  2. kernel.shmall = 1073741824
  3. kernel.shmmni = 4096

Ниже приведена часть документа по установке Oracle, предоставленного redhat6 о совместной памяти:



ipcs -a - это выходная информация по умолчанию. Вывести информацию обо всех методах межпроцессного взаимодействия в текущей системе.

ipcs -m выводит информацию об использовании разделяемой памяти для межпроцессного взаимодействия

ipcs -s выводит информацию, которая использует сигналы для межпроцессного взаимодействия

Контроль формата вывода

ipcs -t подробное время изменения выходной информации

ipcrm -M shmkey удаляет сегмент общей памяти, созданный с помощью shmkey

ipcrm -m shmid удаляет сегмент общей памяти, идентифицируемый shmid

ipcrm -S semkey удалить сигналы, созданные с помощью semkey

ipcrm -s semid удаляет сигнал, идентифицированный semid

Обзор межпроцессного взаимодействия

Linux межпроцессное взаимодействие разработано из следующих частей:

Раннее межпроцессное взаимодействие UNIX: включая каналы, FIFO и сигналы.

На основе межпроцессного взаимодействия сокетов.

В Linux команды, относящиеся к IPC, включают: ipcs, ipcrm (выпуск IPC),

Конкретное использование сводится к следующему:

1. Показать все объекты IPC

3. Показать все семафоры

4. Показать всю общую память

5. Показать подробную информацию об объектах IPC

id соответствует shmid, semid, msgid и т. д. -q соответствует типу объекта (очереди), используйте -s для просмотра деталей семафора и -m для просмотра общей памяти.

6. Отображение предельного размера объектов IPC

-m соответствует типу объекта, необязательные параметры включают -q, -m, -s.

7. Отображение отношения разрешений объектов IPC

8. Отобразите идентификатор процесса недавно посещенного объекта IPC.

9. Отображение последнего времени работы объектов МПК

10. Отображение текущего состояния объектов IPC

Команда ipcs в Linux не поддерживает инструкции -b и -o в UNIX.Так же, инструкции -l и -u не поддерживаются в UNIX, поэтому вам следует обратить внимание на эту проблему при написании кроссплатформенных сценариев.

Читайте также: