• Если прерывание существенно для нас, мы непосредственно обрабатываем его (см. блок операторов case IIR_MSR
).
Где в программе очищать источник прерывания — это зависит от ваших аппаратных средств и от выбранной схемы уведомления. При использовании SIGEV_INTR в сочетании с
Такой сценарий как ISR, возвращающий SIGEV_THREAD, повергает меня в дикий ужас. Настоятельно рекомендую по возможности избегать этого «приема».
В вышеприведенном примере с программированием последовательного порта мы приняли решение использовать функцию for
.
Напрашивается естественный вопрос: «Когда и какую функцию выбирать?»
Наиболее очевидное преимущество
Вот что происходит, когда мы используем
Поток управления при использовании
Выполняющийся поток («Поток 1») прерывается, и мы переключаемся в ядро. Ядро сохраняет контекст «Потока 1». Затем ядро смотрит, кто ответственен за обработку данного прерывания и решает, что это «ISR». Ядро настраивает контекст для «ISR» и передает ему управление. «ISR» опрашивает аппаратуру и решает возвратить struct sigevent
. Ядро отмечает возвращаемое событие, выясняет, кто должен его обработать, и переводит их в состояние READY. Это может привести к планированию ядром другого потока, «Потока 2».
Теперь давайте сопоставим это с тем, что будет происходить при использовании
Поток управления при использовании
В этом случае путь обслуживания прерываний намного короче. Мы выполнили одно переключение контекста от выполнявшегося потока («Поток 1») в ядро. Вместо второго переключения контекста в ISR ядро просто «притворилось», что получило от ISR struct sigevent
и среагировало на него, запланировав «Поток 2».
Теперь вы думаете: «Великолепно! Забудем про
Это не такая хорошая идея, как кажется на первый взгляд, потому что вы можете и не захотеть просыпаться от каждого прерывания, генерируемого аппаратурой! Вернитесь к примеру, который приведен выше — событие там возвращалось только тогда, когда изменялся регистр состояния модема, а не по приему символа, изменению регистра состояния линии или опустошению буфера передачи.
В этом случае, особенно если бы последовательный порт принимал символы (которые вы хотели бы проигнорировать), вы бы потратили много времени впустую на перепланирование своего потока — и только ради того, чтобы он проанализировал состояние последовательного порта и принял решение, что ничего делать не надо. В данном случае все бы выглядело примерно так:
Поток управления при использовании
Происходящее по сути заключается в том, что вы вызываете переключение контекста для перехода к «Потоку 2», он опрашивает аппаратуру и понимает, что делать ничего не требуется, и это влечет за собой еще одно лишнее переключение контекста обратно в «Поток 1».
Вот что произошло бы, если бы вы применили функцию