BeOS - статьи

       

Отступление 2. Сообщения - отправители, диспетчеры, обработчики, прерывания.


В первой части введения мы уже задавались вопросом - как это все программы умудряются работать одновременно? - и частично на него ответили. Необъясненным осталось то, как же всё-таки все эти куски, которые считают, что каждый из них - чуть ли не единственный на белом свете, взаимодействуют с друг другом в многозадачной операционной системе.

Ответ простой - они обмениваются телеграммами/письмами/SMS-ками/бандеролями/и даже грузовыми контейнерами:) - т.е. сообщениями (в unix-мире больше распространена концепция сигналов - signals, в BeOS signals реализованы в слое эмуляции POSIX).

Щелкнул мышкой - драйвер сработал, послал сообщение InputServer-у, тот - ApplicationServer-у, AppServer - в свою очередь - программе.

Хочет программа что либо нарисовать - сообщение AppServer-у, а уж доля того - общаться с драйверами видеокарты.

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

1)отправке сообщений - отправитель в BeOS "называется" BMessenger,

2)приему-перехвату сообщений и решению, что с ними дальше делать (диспетчеризация) - этим занимается цикл приема и распределения сообщений - message loop, BLooper в BeOS,

3)обработке сообщений (обработчик по английски - handler) - BHandler в BeOS.

(Как вы могли догадаться, названия компонент-классов BeAPI начинаются с 'B'.)

Теперь немножко о самих BeOS-сообщениях, для тех знатоков, кто сталкивался с сообщениями в других ОС/платформах. Их отличительное качество - практически "свободный" формат. Единственный обязательный член BMessage - признак "ЧТО" (what). Например, если в сообщении, полученном BeOS-приложением этот what==B_ARGV_RECEIVED (константа, определенная в системе) - это означает, что программа была запущена из командной строки и там имеются аргументы - см. параграф про main().

А дальше (я не зря упомянул не только телеграммы, но и бандероли, и грузовые контейнеры) - в теле сообщения может содержаться практически все что угодно, любого размера. В теории - хоть DVD-диск упакуй туда.
Но не рекомендую:)

Раз уж мы вдарились в объяснения, как работает многозадачная/ многопоточная OS, можно спуститься поближе к земле, то есть к кремнию и железу, и пояснить, на чем все это основано. То есть, рассказать о прерываниях. Знатоки, а также ленивые и нелюбопытные могут смело пропустить нижеследующее безо всякого ущерба.

Есть два способа реагировать на изменения в обстановке - программный опрос (polling) и прерывания (interrupts).

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

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

Второй - прерывания. Когда какому-нибудь устройству или программе невтерпеж пообщаться (например, буфер последовательного порта уже почти забит данными из модема) - они "звонят" процессору - выставляют запрос на прерывание, тот самый печально известный IRQ (interrupt request). Дальше начинается некоторая машинерия - кого обслужить первым и т.д., но, в конечном счете, запоминается текущее состояние системы, выполнение предыдущих программ прекращается (откладывается), и система переходит на выполнение кода, указанного в запросе на прерывание.

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

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

Для первого используются прерывания от системного таймера, для второго - используются так называемые программные прерывания. Аналогию с телефоном/пэйджером/SMS можете додумать сами :)

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


А выглядит он, в сокращенном виде, так:

-------------------------------- main() { KrutajaProgramma.Run() ------------------------------- или так: main() { SuperPuperProgramma->Run() --------------------------------

Этот Run() - метод класса BApplication, запускающий главный цикл - приемник/диспетчер/обработчик сообщений для BeOS-программы в целом.

Охх, опять эти грабли, это "знает почти достаточно" - классы, методы, энкапсуляция, наследование, полиморфизм и прочие ругательства...боюсь что начало этого цикла статей так и будет состоять из сплошных отступлений. Может, отложим до завтра?:) Да и караул уже устал.

Разве что сейчас можно упомнять для знатоков, что be_app из предыдущей главки - это глобальный (доступный всем компонентам программы) указатель на объект этой программы. Переменная с таким именем создается автоматически, при создании объекта-наследника BApplication.

(В данном случае be_app == SuperPuperProgramma или be_app == &KrutajaProgramma). А в связи с отступлением про сообщения, надо упомянуть также то, что BApplication является наследником BLooper и BHandler.

А для тех, кто не устал и полон энтузиазма запустить свою первую BeOS-программу - может от Эрика Шеперда и Макса "Базы" Базарова.

       


Содержание раздела