МЕНЮ


Фестивали и конкурсы
Семинары
Издания
О МОДНТ
Приглашения
Поздравляем

НАУЧНЫЕ РАБОТЫ


  • Инновационный менеджмент
  • Инвестиции
  • ИГП
  • Земельное право
  • Журналистика
  • Жилищное право
  • Радиоэлектроника
  • Психология
  • Программирование и комп-ры
  • Предпринимательство
  • Право
  • Политология
  • Полиграфия
  • Педагогика
  • Оккультизм и уфология
  • Начертательная геометрия
  • Бухучет управленчучет
  • Биология
  • Бизнес-план
  • Безопасность жизнедеятельности
  • Банковское дело
  • АХД экпред финансы предприятий
  • Аудит
  • Ветеринария
  • Валютные отношения
  • Бухгалтерский учет и аудит
  • Ботаника и сельское хозяйство
  • Биржевое дело
  • Банковское дело
  • Астрономия
  • Архитектура
  • Арбитражный процесс
  • Безопасность жизнедеятельности
  • Административное право
  • Авиация и космонавтика
  • Кулинария
  • Наука и техника
  • Криминология
  • Криминалистика
  • Косметология
  • Коммуникации и связь
  • Кибернетика
  • Исторические личности
  • Информатика
  • Инвестиции
  • по Зоология
  • Журналистика
  • Карта сайта
  • Interprocess Communication

    Interprocess Communication

    Лекция №17

    Interprocess Communication

    Мы с вами говорили, что далее речь пойдет о разделяемых ресурсах,

    доступ к которым может осуществляться со стороны произвольных процессов, в

    общем случае, в произвольном порядке. Эти ресурсы доступны любому

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

    такой схемы возникают две принципиальные проблемы:

    1. Именование;

    2. Синхронизация;

    Проблемы именования связаны с тем, что родственных связей нет и по

    наследству передать ничего нельзя.

    Если проблема именования решена, то возникает проблема синхронизации

    доступа - как организовать обмен с ресурсами, чтобы этот обмен был

    корректным. Если у нас есть, например, ресурс “оперативная память”, то

    когда один процесс еще не дописал информацию, а другой процесс уже прочитал

    весь блок, то возникает некорректная ситуация.

    Решения этих проблем мы и будем рассматривать.

    Проблема именования решается за счет ассоциирования с каждым ресурсом

    некоторого ключа. В общем случае это целочисленное значение. То есть при

    создании разделяемого ресурса его автор приписывает ему номер и определяет

    права доступа к этому ресурсу. После этого любой процесс, который укажет

    системе, что он хочет общаться с разделяемым ресурсом с ключом N, и

    обладает необходимыми правами доступа, будет допущен для работы с этим

    ресурсом.

    Однако такое решение не является идеальным, так как вполне возможна

    коллизия номеров - когда совпадают номера разделяемых ресурсов. В этом

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

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

    генерации уникального ключа используется функция ftok

    #include

    #include

    key_t ftok(char *s, char c);

    Суть ее действия - по текстовой строке и символу генерируется

    уникальное для каждой такой пары значение ключа. После этого

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

    для подтверждения использования ресурса. Более того, для исключения

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

    строку" путь к некоторому своему файлу. Второй аргумент - символьный,

    который позволяет создавать некоторые варианты ключа, связанного с этим

    именем, этот аргумент называется проектом (project). При таком подходе

    можно добиться отсутствия коллизий.

    Давайте посмотрим конкретные средства работы с разделяемыми

    ресурсами.

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

    Общая схема работы с разделяемыми ресурсами такова - есть некоторый

    процесс-автор, создающий ресурс с какими-либо параметрами. При создании

    ресурса разделяемой памяти задаются три параметра - ключ, права доступа и

    размер области памяти. После создания ресурса к нему могут быть подключены

    процессы, желающие работать с этой памятью. Соответственно, имеется

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

    же правилам, что и ключ для создания ресурса. Понятно, что здесь имеется

    момент некоторой рассинхронизации, который связан с тем, что потребитель

    разделяемого ресурса (процесс, который будет работать с ресурсом, но не

    является его автором) может быть запущен и начать подключаться до запуска

    автора ресурса. В этой ситуации особого криминала нету, так как имеются

    функции управления доступом к разделяемому ресурсу, с использованием

    которых можно установить некоторые опции, определяющие правила работы

    функций, взаимодействующих с разделяемыми ресурсами. В частности,

    существует опция, заставляющая процесс дождаться появления ресурса. Это

    также, может быть, не очень хорошо, например, автор может так и не

    появиться, но другого выхода нету, это есть некоторые накладные расходы.

    Вот в общих словах - что есть что.

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

    с разделяемыми ресурсами.

    Первая функция - создание общей памяти.

    int shmget (key_t key, int size, int shmemflg);

    key - ключ разделяемой памяти

    size - размер раздела памяти, который должен быть создан

    shmemflg - флаги

    Данная функция возвращает идентификатор ресурса, который

    ассоциируется с созданным по данному запросу разделяемым ресурсом. То есть

    в рамках процесса по аналогии с файловыми дескрипторами каждому

    разделяемому ресурсу определяется его идентификатор. Надо разделять ключ -

    это общесистемный атрибут, и идентификатор, используя который мы работаем с

    конкретным разделяемым ресурсом в рамках процесса.

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

    “память” (в этом случае во флагах должен быть указан IPC_CREAT)?, а также

    можно подключиться к существующему разделяемому ресурсу. Кроме того, в

    возможных флагах может быть указан флаг IPC_EXECL, он позволяет проверить и

    подключиться к существующему ресурсу - если ресурс существует, то функция

    подключает к нему процесс и возвращает код идентификатора, если же ресурс

    не существует, то функция возвращает -1 и соответствующий код в errno.

    Следующая функция - доступ к разделяемой памяти:

    char *shmat(int shmid, char *shmaddr, int shmflg);

    shmid - идентификатор разделяемого ресурса

    shmaddr - адрес, с которого мы хотели бы разместить разделяемую

    память

    При этом, если значение shmaddr - адрес, то память будет подключена,

    начиная с этого адреса, если его значение - нуль, то система сама подберет

    адрес начала. Также в качестве значений этого аргумента могут быть

    некоторые предопределенные константы, которые позволяют организовать, в

    частности выравнивание адреса по странице или началу сегмента памяти.

    shmflg - флаги. Они определяют разные режимы доступа, в частности,

    есть флаг SHM_RDONLY.

    Эта функция возвращает указатель на адрес, начиная с которого будет

    начинаться запрашиваемая разделяемая память. Если происходит ошибка, то

    возвращается -1.

    Хотелось бы немного поговорить о правах доступа. Они реально могут

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

    поддерживается закрытие области данных на чтение или на запись, то в этом

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

    первых, они не будут работать, так как мы получаем указатель и начинаем

    работать с указателем, как с указателем, и общая схема здесь не

    предусматривает защиты. Второе, можно программно сделать так, чтобы

    работали флаги, но тогда мы не сможем указывать произвольный адрес, в этом

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

    памяти некоторые свои адреса, обращение к которым будет создавать заведомо

    ошибочную ситуацию, возникнет прерывание процесса, во время которого

    система посмотрит - кто и почему был инициатором некорректного обращения к

    памяти, и если тот процесс имеет нужные права доступа - система подставит

    нужные адреса, иначе доступ для процесса будет заблокирован. Это похоже на

    установку контрольной точки в программе при отладке, когда создавалась

    заведомо ошибочная ситуация для того, чтобы можно было прервать процесс и

    оценить его состояние.

    Третья функция - открепление разделяемой памяти:

    int shmdt(char *shmaddr);

    shmaddr - адрес прикрепленной к процессу памяти, который был получен

    при подключении памяти в начале работы.

    Четвертая функция - управление разделяемой памятью:

    int shmctl(int shmid, int cmd, struct shmid_ds *buf);

    shmid - идентификатор разделяемой памяти

    cmd - команда управления.

    В частности, могут быть команды: IPC_SET (сменить права доступа и

    владельца ресурса - для этого надо иметь идентификатор автора данного

    ресурса или суперпользователя), IPC_STAT (запросить состояние ресурса - в

    этом случае заполняется информация в структуру, указатель на которую

    передается третьим параметром, IPC_RMID (уничтожение ресурса - после того,

    как автор создал процесс - с ним работают процессы, которые подключаются и

    отключаются, но не уничтожают ресурс, а с помощью данной команды мы

    уничтожаем ресурс в системе).

    Это все, что касается функций управления разделяемой памятью.

    Передача сообщений.

    [pic]

    Следующим средством взаимодействия процессов в системе IPC - это

    передача сообщений. Ее суть в следующем: в системе имеется так называемая

    очередь сообщений, в которой каждое сообщение представляет из себя

    структуру данных, с которой ассоциирован буфер, содержащий тело сообщения и

    признак, который называется типом сообщения. Очередь сообщений может быть

    рассмотрена двояко:

    1. очередь рассматривается, как одна единственная сквозная очередь, порядок

    сообщений в которой определяется хронологией их попадания в эту очередь.

    2. кроме того, так как каждое сообщение имеет тип (на схеме - буква рядом с

    номером сообщения), то эту очередь можно рассматривать, как суперпозицию

    очередей, связанную с сообщениями одного типа.

    Система IPC позволяет создавать разделяемый ресурс, называемый

    “очередь сообщений” - таких очередей может быть произвольное количество. По

    аналогии с разделяемой памятью - мы можем создать очередь, подключиться к

    ней, послать сообщение, принять сообщение, уничтожить очередь и т.д.

    Рассмотрим функции работы с очередями сообщений:

    Создание очереди сообщений:

    int msgget(key_t key, int flags);

    В зависимости от флагов при обращении к данной функции либо создается

    разделяемый ресурс, либо осуществляется подключение к уже

    существующему.

    Отправка сообщения:

    int msgsnd( int id, struct msgbuf *buf, int size, int flags);

    id - идентификатор очереди сообщения;

    struct msgbuf {

    long type; /* тип сообщения */

    char mtext[s] /* указатель на тело сообщения */

    }

    size - размер сообщения, здесь указывается размер сообщения,

    размещенного по указателю buf;

    flags - флаги, в частности, флагом может быть константа IPC_NOWAIT.

    При наличии такого флага будут следующие действия - возможна ситуация,

    когда буфера, предусмотренные системой под очередь сообщений,

    переполнены. В этом случае возможны два варианта - процесс будет

    ожидать освобождения пространства, если не указано IPC_NOWAIT, либо

    функция вернет -1 (с соответствующим кодом в errno), если было указано

    IPC_NOWAIT.

    Прием сообщения:

    int msgrcv( int id, struct msgbuf *buf, int size, long type, int

    flags);

    id - идентификатор очереди;

    buf - указатель на буфер, куда будет принято сообщение;

    size - размер буфера, в котором будет размещено тело сообщения;

    type - если тип равен нулю, то будет принято первое сообщение из

    сквозной очереди, если тип больше нуля, то в этом случае будет принято

    первое сообщение из очереди сообщений, связанной с типом, равным

    значению этого параметра.

    flags - флаги, в частности, IPC_NOWAIT, он обеспечит работу запроса

    без ожидания прихода сообщения, если такого сообщения в момент

    обращения функции к ресурсу не было, иначе процесс будет ждать.

    Управление очередью:

    int msgctl( int id, int cmd, struct msgid_dl *buf);

    id - идентификатор очереди;

    cmd - команда управления, для нас интерес представляет IPC_RMID,

    которая уничтожит ресурс.

    buf - этот параметр будет оставлен без комментария.

    Мы описали два средства взаимодействия между процессами. Что же мы

    увидели? Понятно, что названия и описания интерфейсов мало понятны. Прежде

    всего следует заметить то, что как только мы переходим к вопросу

    взаимодействия процессов, у нас возникает проблема синхронизации. И здесь

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

    разделяемой памятью или очередью сообщений, в системе может оставаться

    “хлам”, например, процессы, которые ожидают сообщений, которые в свою

    очередь не были посланы. Так, если мы обратились к функции получения

    сообщений с типом, которое вообще не пришло, и если не стоит ключ

    IPC_NOWAIT, то процесс будет ждать его появления, пока не исчезнет ресурс.

    Или мы можем забыть уничтожить ресурс (и система никого не поправит) - этот

    ресурс останется в виде загрязняющего элемента системы.

    Когда человек начинает работать с подобными средствами, то он берет

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

    первый набор проблем - системная синхронизация и аккуратность. Вторая

    проблема - синхронизация данных, когда приемник и передатчик работают

    синхронно. Заметим, что самый плохой по синхронизации ресурс из

    рассмотренных нами - разделяемая память. Это означает, что корректная

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

    средств синхронизации, и, в частности, некоторым элементом синхронизации

    может быть очередь сообщений. Например, мы можем записать в память данные и

    послать сообщение приемнику, что информация поступила в ресурс, после чего

    приемник, получив сообщение, начинает считывать данные. Также в качестве

    синхронизирующего средства могут применяться сигналы.

    И это главное - не язык интерфейсов, а проблемы, которые могут

    возникнуть при взаимодействии параллельных процессов.

    Лекция №18

    К сегодняшнему дню мы разобрали два механизма взаимодействия процессов

    в системе IPC - это механизм общей (или разделяемой) памяти и механизм

    сообщений. Мы с вами выяснили, что одной из основных проблем, возникающей

    при взаимодействии процессов, является проблема синхронизации. Ярким

    примером механизма, для которого эта проблема является наиболее острой,

    является механизм взаимодействия процессов с использованием разделяемой

    памяти.

    Вы помните, что механизм разделяемой памяти позволяет создавать

    объект, который становится доступным всем процессам, подтвердившим ключ

    доступа к этому объекту, а также имеют соответствующие права. После этого

    общая память становится, с точки зрения каждого из этих процессов, как бы

    фрагментом адресного пространства каждого из них, к которому этот процесс

    может добираться через указатель этого адресного пространства. С другой

    стороны нет никаких средств, которые позволили бы синхронизовать чтение и

    запись в эту область данных. Так как в эту область данных одновременно

    имеет доступ произвольное количество процессов, то проблема синхронизации

    здесь имеет место быть.

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

    память, но еще не закончил, но другой процесс не дождался завершения

    записи, считал и начал пользоваться этой информацией. В этом случае

    возможны коллизии. Т.е. без синхронизации использовать механизм разделяемой

    памяти невозможно.

    Следующий механизм, который мы с вами рассмотрели - очередь сообщений.

    Имеется возможность совместной работы с разделяемым объектом, который

    называется очередь сообщений. Имеется сообщение, которое состоит из

    некоторого спецификатора типа, и некоторого набора данных. Процесс,

    подтвердив ключ и имея права доступа к этому разделяемому ресурсу, может

    осуществлять действия по записи сообщений в очередь, и по чтению сообщений

    из очереди.

    Порядок чтения и записи сообщений из очереди соответствует названию

    этой структуры - очередь. Кроме того, за счет того, что каждое сообщение

    типизировано, есть возможность рассмотрения этой очереди с нескольких точек

    зрения. Первая точка зрения - это одна очередь и порядок в ней

    хронологический. Вторая точка зрения - это возможность представление этой

    очереди в виде нескольких очередей, каждая из которых содержит элементы

    определенного типа.

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

    средство передача данных, и как средство синхронизации (понятно каким

    образом).

    Итак, к сегодняшнему дню мы познакомились с двумя этими механизмами.

    Напомню, как только мы переходим к работе от однопроцессной задачи к задаче

    многопроцессной, у нас сразу же возникают проблемы, связанные с тем, что

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

    Это ответственность по синхронизации доступа к разделяемой памяти,

    ответственность за правильность подпрограммы, занимающейся приемом и

    передачей сообщений и т.д. Можно, например, ошибиться в механизме передачи

    и приема сообщений за счет того, что какой-то процесс будет бесконечно

    долго ожидать несуществующее сообщение, то, которое никогда в очереди не

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

    зависания процессов, могут образоваться неосвобожденные ресурсы ("мусор"),

    и это приводит к деградации системы.

    Сейчас мы напишем следующую программу: первый процесс будет читать

    некоторую текстовую строку из стандартного ввода и в случае, если строка

    начинается с буквы 'a', то эта строка в качестве сообщения будет передана

    процессу А, если 'b' - процессу В, если 'q' - то процессам А и В и затем

    будет осуществлен выход. Процессы А и В распечатывают полученные строки на

    стандартный вывод.

    Основной процесс

    #include

    #include

    #include

    #include

    Страницы: 1, 2, 3, 4, 5


    Приглашения

    09.12.2013 - 16.12.2013

    Международный конкурс хореографического искусства в рамках Международного фестиваля искусств «РОЖДЕСТВЕНСКАЯ АНДОРРА»

    09.12.2013 - 16.12.2013

    Международный конкурс хорового искусства в АНДОРРЕ «РОЖДЕСТВЕНСКАЯ АНДОРРА»




    Copyright © 2012 г.
    При использовании материалов - ссылка на сайт обязательна.