QNX/UNIX: Анатомия параллелизма
QNX/UNIX: Анатомия параллелизма читать книгу онлайн
Книга адресована программистам, работающим в самых разнообразных ОС UNIX. Авторы предлагают шире взглянуть на возможности параллельной организации вычислительного процесса в традиционном программировании. Особый акцент делается на потоках (threads), а именно на тех возможностях и сложностях, которые были привнесены в технику параллельных вычислений этой относительно новой парадигмой программирования. На примерах реальных кодов показываются приемы и преимущества параллельной организации вычислительного процесса. Некоторые из результатов испытаний тестовых примеров будут большим сюрпризом даже для самых бывалых программистов. Тем не менее излагаемые техники вполне доступны и начинающим программистам: для изучения материала требуется базовое знание языка программирования C/C++ и некоторое понимание «устройства» современных многозадачных ОС UNIX.
В качестве «испытательной площадки» для тестовых фрагментов выбрана ОСРВ QNX, что позволило с единой точки зрения взглянуть как на специфические механизмы микроядерной архитектуры QNX, так и на универсальные механизмы POSIX. В этом качестве книга может быть интересна и тем, кто не использует (и не планирует никогда использовать) ОС QNX: программистам в Linux, FreeBSD, NetBSD, Solaris и других традиционных ОС UNIX.
Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних чтение данного контента СТРОГО ЗАПРЕЩЕНО! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту [email protected] для удаления материала
• Процессы QNX сохраняют все качества таковых и в UNIX вообще: они являются изолированными сущностями, которые взаимодействуют, если это необходимо, используя достаточно тяжеловесные (расточительные) механизмы IPC. Собственно, в этом и ценность процессов с их изолированными адресными пространствами — это механизм обеспечения высокой надежности и живучести приложений. Но QNX, не сужая спектр общепринятых IPC-механизмов, привносит совершенно новый «слой» инструментария взаимодействия — обмен сообщениями микроядра. При этом «проницаемость» процессов как отдельных клеток живого организма становится много выше, нисколько не снижая их «защищенности».
Но у нас есть две принципиально различные альтернативы для выражения этого «слоя» взаимодействий в своем программном коде: базовый механизм обмена сообщениями (низкоуровневая техника, известная еще со времен QNX 4.X) и механизм менеджера ресурса. Делать выбор между ними приходится на этапе раннего эскизного проектирования системы, поскольку перестраивать систему с одного механизма на другой в ходе развития — достаточно трудоемкий процесс, который может потребовать пересмотра и архитектурных основ развиваемого проекта.
Поэтому, приступая к проектированию нового проекта, мы должны априорно, до начала фактической разработки, отчетливо представлять, что выигрываем и что проигрываем, используя тот или иной механизм реализации обмена сообщениями.
Две стороны единого механизма
При рассмотрении базовой для QNX (собственно, для всех микроядерных ОС) техники обмена сообщениями в сравнении с технологией написания менеджеров ресурсов не покидает ощущение поразительной схожести происходящих в обоих случаях процессов. В этом нет ничего удивительного, поскольку инструментарий менеджеров ресурсов — это только система внешних «оберток» над базовым механизмом обмена сообщениями.
Для эффективного применения той или иной альтернативной технологии мы должны иметь возможность проанализировать многие сравнительные показатели выбираемого инструментария: простота, гибкость, эффективность, трудоемкость реализации, возможности внесения изменений при развитии проекта и на этапе его последующего сопровождения. Этим мы и займемся в оставшейся части главы.
Простота и трудоемкость
Механизм прямого обмена сообщениями крайне просто выражается в программном коде. Когда достигнута полная ясность в значениях адресных параметров обмена, необходимо всего лишь несколько операторов, чтобы заставить все это «крутиться».
Со стороны сервера, например, это выглядит так:
int chid = ChannelCreate(0);
...
while (true) {
struct _msg_info info;
int rcvid = MsgReceive(chid, &bufin, sizeof(bufin), &info);
if (rcvid < 0) exit(EXIT_FAILURE);
if (MsgReply(rcvid, EOK, &bufou, sizeof(bufou) < 0) exit(EXIT_FAILURE);
}
Co стороны клиента:
int coid = ConnectAttach(node, pid, chid, _NTO_SIDE_CHANNEL, 0);
if (coid < 0) exit(EXIT_FAILURE);
...
while(...)
if (MsgSend(coid, &bufou, sizeof(bufou), &bufin, sizeof(bufin)) == -1)
exit(EXIT_FAILURE);
}
Код для реализации того же обмена, но организованного как менеджер ресурса, будет как минимум в несколько раз объемнее (образцы менеджеров мы уже видели ранее по тексту). Кроме того, по большей части он будет состоять из заполнения полей некоторых внутренних структур, используемых библиотеками менеджера ресурсов или пула потоков. На первый поверхностный взгляд такой код маловразумителен.
С другой стороны, весь достаточно объемный код любогоменеджера ресурса — это очередное повторение одного и того же общего шаблона для написания менеджеров. При некоторых минимальных навыках написание самых замысловатых менеджеров ресурсов становится совершенно рутинным занятием, не превышающим по трудоемкости написание простого обмена сообщениями. Большим подспорьем здесь является наличие в комплекте технической документации QNX огромного (более 80 страниц) раздела, исчерпывающе описывающего технику создания менеджеров ресурсов; по качеству и скрупулезности изложения это одна из лучших частей всей технической документации.
Гибкость и мобильность
При установлении соединения техника простого обмена сообщениями в качестве адресата сообщений (сервера) использует «магическую тройку» (триплет [1]) параметров ND, PID и CHID, где:
•
ND
•
PID
•
CHID
В этой адресации, пожалуй, и кроется самая главная причина негибкости механизма обмена сообщениями. Дескриптор сетевого узла
nd
netmgr_strtond()
Гораздо хуже дело обстоит с
pid
chid
Р. Кертен [1] отмечает, что существует множество способов нахождения этой адресной триады, и перечисляет некоторые из них:
1. Открыть файл с известным именем и сохранить в нем ND/PID/CHID…
2. Использовать для объявления идентификаторов ND/PID/CHID глобальные переменные программы…
3. Занять часть пространства имен путей и стать администратором ресурсов.
Не вдаваясь в подробный анализ (вы это можете сделать сами), отметим, что 1-й способ — крайне искусственный и негибкий (особенно в сетевой среде), 2-й — крайне ограничен и применим лишь к узкому кругу задач, а 3-й способ подводит нас к применению совсем другой, альтернативной технологии с используемыми ею принципами адресации.
Несколько, безусловно, интересных и заслуживающих внимания вариаций на тему техники обмена сообщениями предлагает В. Зайцев в приложении, которое следует за данной главой.
Пользуясь случаем, внесем и мы свою лепту в «копилку» способов вычисления адресной триады и увязывания клиента с соответствующим сервером. В тех нечастых случаях, когда требуется обеспечить максимально возможную плотность потока обмена (об этом см. далее), а информационный канал желательно создать на базе именно прямого обмена сообщениями, мы предлагаем оформлять серверный процесс одновременно и как специальный менеджер ресурса, и как канал прямого обмена сообщениями. При этом клиент, пользуясь адресацией пути к менеджеру, запрашивает его по
read()
devctl()