QNX/UNIX: Анатомия параллелизма [заметки]
1
По тому же принципу писались книги, ставшие самыми информативными источниками в мировой практике, например описания Даниэля Нортона по MS-DOS или Джеффри Рихтера по Win32.
2
Все технические описания QNX API сформированы в ориентации на классический С. Напротив, все используемые в тексте примеры кода излагаются в синтаксисе С++, а прилагаемые к тексту приложения транслированы в С++. Это обусловлено рядом аргументов, которые обсуждать не будем, но отметим, что такое различие подходов в любом случае расширяет информационную базу относительно использования QNX API.
3
В книге в примерах кода мы часто используем русскоязычные символьные константы для вывода сообщений, например >"Получен сигнал SIGINT"
, что способствует большей доходчивости обсуждаемого кода. Однако в файлах работающих приложений, представленных в архиве, вы увидите только англоязычные эквиваленты выводимых сообщений, поскольку работающие примеры кода являются консольными приложениями, а текстовая консоль QNX не русифицируема в принципе и графические псевдотерминалы (pterm, xterm) имеют определенные сложности.
4
Это положение напрямую диктуется определением «слабосвязанных процессов», впервые сформулированным Э. Дейкстрой [10]. Заметим, что фундаментальная и стройная «картина мира», выстроенная Э. Дейкстрой и считающаяся классикой, исчерпывающе («необходимо и достаточно») описывает систему процессов равного приоритета. Расширение реальных систем атрибутом приоритета затуманивает прозрачность этой модели и делает все гораздо сложнее…
5
На сегодняшний день практически ни одна из ОС UNIX уже не может быть отнесена чисто к System V или BSD, во многом исходя именно из требования совместимости с POSIX, который требует одновременного наличия и того и другого API (хотя в каждом случае комплиментарный набор API реализуется как «обертка» к базовому). Одними из первых (к 1997–1998 гг.) ОС, поддерживающих оба набора API, стали Sun Solaris 2.6 и Digital Unix 4.0B [3].
6
При общей истории UNIX, начинающейся с 1971 г. [7], две ветви API — BSD и System V — в их современном виде сформировались достаточно поздно: BSD к 1983 г., a System V к 1987 г. [3, 7]. Но многие IPC-механизмы System V (например, семафоры) сформировались по времени заметно раньше своих аналогов из BSD. Как отмечается в [3]: «Информация об истории разработки и развитии функций System V IPC не слишком легко доступна <…> очереди сообщений, семафоры и разделяемая память этого типа были разработаны в конце 70х в одном из филиалов Bell Laboratories в городе Колумбус… Эта версия называлась Columbus Unix, или СВ Unix».
7
[4]: глава Д. Алексеева «Получение системной информации».
8
Здесь Робачевский мимоходом расширяет понятие процесса и на программу, представленную, например, текстом для интерпретатора shell, или языков Perl, Tcl/Tk, или других интерпретаторов. В контексте нашего обсуждения в случаях выполнения таких «программ» «процессом» будет процесс, интерпретирующий текст скрипта, и именно к нему в полной мере относятся все детали нашего рассмотрения относительно процессов.
9
Здесь используется терминология [7]; терминология и аббревиатуры для различных клонов UNIX несколько различаются между собой в описывающих их литературных источниках.
10
Здесь многое зависит от расстановки приоритетов. Если вы хотите, чтобы всякий, читающий ваш код, тут же воскликнул: «Ну и крутой же парень написал такое!», заведомо используйте >spawn()
. При желании сделать код максимально элегантным используйте >fork()
, а если ставится задача хорошей читаемости и ясности кода, то очень часто достаточно и >system()
.
11
Детали создания потока и и частности передачи ему параметра обстоятельно рассматриваются далее.
12
Напоминаем, что листинги, названия которых выделены подобным образом (на сером фоне), представляют собой законченные приложения. Соответствующие файлы можно найти в архивах; они могут быть воспроизведены или модифицированы для тонкого анализа результатов.
13
Тем не менее это вовсе не означает, что следует непосредственно использовать вызов >spawn()
, ведь он самый трудоемкий и чреват ошибками.
14
Часто в публикациях ссылаются на расширения реального времени POSIX 1003b (1993). Но POSIX 1003b не описывают группу >pthread_*
, хотя именно в этой редакции определены семафоры >sem_t
. У. Стивенс [2] указывает, что программные потоки POSIX определены в редакции 1003.1 (1995).
15
Клонирование многопоточных процессов с помощью >fork()
— это отдельная песня. Хотя POSIX и предусматривает реализацию (>pthread_atfork()
) такой возможности, до конца не ясно, как это работает. API QNX предоставляет эту возможность, но предупреждает, что пользователь сам отвечает за последствия. Детали механизма >pthread_atfork()
см. в справочном руководстве QNX.
16
Собственно с этим и связано употребление применительно к потокам названия «легкие процессы». Впервые этот термин (LWP — lightweight process) ввела в своей технической документации для обозначения понятия, эквивалентного потоку, фирма Sun Microsystems.
17
Эта схема PID/TID описана в POSIX, но выполняется далеко не во всех UNIX-совместимых ОС. Например, вплоть до самых последних редакций ядра Linux (ситуация стала меняться только сейчас) процессы (>fork()
) и потоки (>pthread_create()
) (создавались на базе единого системного вызова (>_clone()
) и TID являлись идентификаторами в едином ряду PID. Это может привести к трудно выявляемым ошибкам при переносе программ между двумя ОС.
18
Русскоязычную терминологию, пусть и не самую благозвучную, мы здесь заимствуем из [12].
19
В литературе неоднократно отмечалось, что ошибки многопоточных программ часто не детерминированы (могут возникать или нет в идентичных условиях исполнения), трудно воспроизводимы и могут быть крайне трудны для локализации.
20
Пользователь может изменять это поле, однако это лишено смысла и не влечет за собой никаких последствий, ведь значением текущего приоритета «управляет» ОС, например для осуществления наследования приоритетов. С другой стороны, иногда целесообразно считать значение именно этого поля, чтобы определить значение динамического приоритета потока, установленного, например, в результате того же наследования.
21
В документации неоднократно упоминается еще одна дисциплина — «адаптивная» (>SCHED_ADAPTIVE
), и даже детально описывается, «как она работает». Видимо, это можно отнести только к тому, что корректировка обширной документации отстает от развития самой системы. На конференции «QNX-Россия 2003» на вопрос по поводу ADAPTIVE-диспетчеризации представители QSSL отвечали так: «Этот вид диспетчеризации был в QNX 4.xx, а в QNX 6.x вместо него введена более продвинутая техника SPORADIC-диспетчеризации». Тем не менее более продвинутая спорадическая диспетчеризация не позволяет абсолютно точно выразить логику адаптивной.
22
Этот тест и его результаты для Linux подсказаны одним из участников (имя нам неизвестно) обсуждений на http://qnxclub.net.forum.
23
Согласно стандарту POSIX установки состояния и типа завершаемости могут быть сделаны только из уже выполняющегося кода потока (при старте потока эти параметры установлены в значения по умолчанию). QNX делает расширение, позволяя установить соответствующие флаги в атрибутной записи еще до создания потока. Подробнее об этом говорилось при обсуждении создания потока.
24
Разница выражается в том, что макрос >pthread_cleanup_push()
расширяется в фрагмент кода, открывающийся скобкой «{» без соответствующей скобки «}», аналогично >pthread_cleanup_pop()
закрывается «}», не имея открывающей скобки. Эти вызовы могут располагаться только парами, в противном случае возникнет лексическая ошибка, обнаруживаемая компилятором.
25
Мы умышленно делаем акцент на этом месте, так как существует «красивая народная легенда» (и это утверждение встречается порой и в литературе), что потоки на периоде выполнения намного эффективнее (в смысле переключения контекста), чем процессы.
26
Здесь применена только простейшая форма «активного объекта»: гораздо сложнее, к примеру, определить деструктор такого объекта. Но именно в своем простейшем виде это многообещающая техника активных объектов.
27
Именно поэтому, наверное, стандарту POSIX так сложно органично согласовать их с нововведениями, например с парадигмой потоков.
28
Наличие круглых скобок после имени сигнала — признак того, что для этих сигналов реакция по умолчанию — принудительное завершение процесса; наличие (+) означает, что для этих сигналов предусмотрено создание дампа завершения, а наличие (-) — для этих сигналов дамп не создается. В квадратных скобках после имени сигнала указано численное значение, соответствующее данному сигналу, как оно определено в QNX.
29
Все это и делает механизм обработки более надежным по сравнению с более ранним механизмом, который описывался выше.
30
Спецификация XSI требует, чтобы процесс использовал либо поле >sa_handler
, либо поле >sa_sigaction
, но не оба поля одновременно (в случае «классической» структуры >sigaction
, см. выше). Реализация QNX за счет объединения двух обработчиков под одним >union
обеспечивает это требование автоматически, хотя определения при этом становятся несколько более громоздкими.
31
Модель очереди сигналов введена главным образом для обеспечения сигналов реального времени и будет рассмотрена ниже.
32
Инициализации, используемые в примерах вида >sigaction act = { &catchint, 0, (sigset_t)0};
, будут зависимыми от системы из-за описанных ранее различий определения >struct sigaction
в разных ОС UNIX.
33
Повторить приложение У. Стивенса в QNX в чистом виде не удастся — оно аварийно завершится по сигналу. Тонкий анализ этого факта интересен сам по себе, но он выходит за рамки нашего рассмотрения. Мы обращаем внимание на это обстоятельство, чтобы лишний раз сделать акцент на достаточно ощутимых отличиях реализаций QNX от схем POSIX (или того, как эти схемы понимаются в других ОС).
34
Функция >SignalProcmask()
имеет свой реентерабельный (безопасный в потоках) эквивалент: >SignalProcmask_r()
.
35
И здесь вопрос не в плагиате. Известно, что Р. Кертен долгое время сотрудничал с QSSL именно по части написания документации, поэтому она во многом следует его манере изложения, хотя более поздняя книга Р. Кертена [1] изложена заметно доходчивее.
36
Функции >SyncMutexRevive()
и >SyncMutexRevive_r()
, из которых вторая является потокобезопасной формой первой, как это описывалось выше, отличаются между собой только способом уведомления об ошибке: первая форма возвращает -1 в случае ошибки и устанавливает >errno
, а вторая непосредственно возвращает код ошибки.
37
Забавно! Речь идет об исчерпании количества рекурсивных захватов для внутреннего мьютекса. Здесь есть некоторое несоответствие с другими объектами синхронизации.
38
Естественно, поток, один из потоков процесса, но оригинальные описания логики обмена сообщениями сформулированы в терминологии процессов, и мы не станем отходить от этой традиции. Это обусловлено, скорее, преемственностью изложений с предыдущими реализациями ОС QNX — 4.X и более ранними, т.к. логика функционирования обмена сообщениями остается практически неизменной на протяжении более 20 лет развития линии QNX.
39
Как и функции >spawn*()
и >exec*()
, API обмена сообщениями предоставляет целые группы вызовов, различающихся суффиксами имен и форматами входных параметров.
40
Вы спросите, почему указатель, возвращаемый >thread_pool_create()
, имеет тип >thread_pool_t*
, а получающий его параметр >thread_pool_start()
определен как >void*
? Это или неаккуратность разработчиков QNX, или глубокая сермяжная правда, которую мы пока не понимаем.
41
Эта техника возникла не «сразу» и не случайно: ее идеология практически сложилась за почти 20 лет развития системы QNX, но не была представлена в виде формальных механизмов. В QNX 6.X оставалось только придать ей формальный вид и обеспечить ее поддержание написанием специальных библиотек.
42
В Интернете доступен прекрасный перевод этого документа, выполненный Владимиром Зайцевым и отредактированный к публикации Сергеем Малышевым: http://qnxclub.net/files/articles/resmgr/resmgr.pdf.gz.
43
Строго говоря, в однопоточных процессах QNX 4 обмен тоже организовывался между потоками, просто там разделение понятий «процесс» и «поток» не имело смысла и поэтому всюду использовался только термин «процесс».
![UNIX — универсальная среда программирования](/storage/book-covers/d7/d75f1c2110bd307783066f75974fe127b44ac9b9.jpg)
В книге американских авторов — разработчиков операционной системы UNIX — блестяще решена проблема автоматизации деятельности программиста, системной поддержки его творчества, выходящей за рамки языков программирования. Профессионалам открыт богатый "встроенный" арсенал системы UNIX. Многочисленными примерами иллюстрировано использование языка управления заданиями shell.Для программистов-пользователей операционной системы UNIX.
![Разработка ядра Linux](/storage/book-covers/57/5719ba267b09e945aaff6a85683397781e966ccc.jpg)
В книге детально рассмотрены основные подсистемы и функции ядер Linux серии 2.6, включая особенности построения, реализации и соответствующие программны интерфейсы. Рассмотренные вопросы включают: планирование выполнения процессов, управление временем и таймеры ядра, интерфейс системных вызовов, особенности адресации и управления памятью, страничный кэш, подсистему VFS, механизмы синхронизации, проблемы переносимости и особенности отладки. Автор книги является разработчиком основных подсистем ядра Linux.
![Виртуальные машины: несколько компьютеров в одном](/storage/book-covers/d3/d3d21efc0138d31faad0917369f9053e064085e5.jpg)
Применение виртуальных машин дает различным категориям пользователей — от начинающих до IT-специалистов — множество преимуществ. Это и повышенная безопасность работы, и простота развертывания новых платформ, и снижение стоимости владения. И потому не случайно сегодня виртуальные машины переживают второе рождение.В книге рассмотрены три наиболее популярных на сегодняшний день инструмента, предназначенных для создания виртуальных машин и управления ими: Virtual PC 2004 компании Microsoft, VMware Workstation от компании VMware и относительно «свежий» продукт — Parallels Workstation, созданный в компании Parallels.
![Недокументированные и малоизвестные возможности Windows XP](/storage/book-covers/3c/3c1be627c1d69a562e3fca9dc54a9a80bbae29e0.jpg)
Книга содержит подробные сведения о таких недокументированных или малоизвестных возможностях Windows XP, как принципы работы с программами rundll32.exe и regsvr32.exe, написание скриптов сервера сценариев Windows и создание INF-файлов. В ней приведено описание оснасток, изложены принципы работы с консолью управления mmc.exe и параметрами реестра, которые изменяются с ее помощью. Кроме того, рассмотрено большое количество средств, позволяющих выполнить тонкую настройку Windows XP.Эта книга предназначена для опытных пользователей и администраторов, которым интересно узнать о нестандартных возможностях Windows.
![Windows Vista. Мультимедийный курс](/storage/book-covers/90/9076fd7cf40e08475c322090e7c5bab39a1bf5f1.jpg)
Эта книга поможет вам разобраться в премудростях операционной системы Windows Vista.Информационная насыщенность учебного материала позволяет утверждать, что мультимедийный курс будет интересен и новичкам, и опытным пользователям.
![Свободные программы и системы в школе](/build/oblozhka.dc6e36b8.jpg)
Курс лекций, включенных в брошюру, знакомит читателя с популярными свободными программами и системами, полезными при преподавании информатики в средней школе. В обзор вошли основы открытых операционных систем, сведения о пакете «офисных» программ OpenOffice.org, коммуникационном пакете Mozilla, графическом редакторе GIMP, современных графических средах GNOME и KDE и других программах.Для преподавателей информатики и методистов, а также для студентов и аспирантов соответствующих специальностей.© 2002-3, Максим Отставнов.© 2002, Андрей Добровольский (раздел 3.1).Использован текст лекций, публиковавшихся автором в приложении к газете «Первое сентября» «Информатика» (http://inf.1september.ru) в 2002-3 г., материалы брошюры «Прикладные свободные программы в школе» (М.: 2003 г.), а также фрагменты статей, ранее публиковавшихся в журналах «Компьютерра» и «Домашний компьютер».Материалы, представленные в этой книге, также доступны в Интернет на странице www.otstavnov.com/fsft на условиях Свободной лицензии ГНУ на документацию (GNU FDL)