Структура событий на самом деле является просто абстракцией, которая скрывает от вас поток выполнения. Где-то на компьютере должен быть запущен какой-то код, который проверяет эти события, а затем вызывает обработчики событий. в C от вас ожидается, что вы сами предоставите этот код («основной цикл» программы). Этот код проверит различные интересующие вас источники событий и вызовет ваши функции обработчика событий.
Затем хитрость заключается в том, как не допустить, чтобы этот основной цикл дико вращал ЦП. Один из простых приемов состоит в том, чтобы основной цикл приостановился на некоторое время, а затем проверил, нужно ли обрабатывать какие-либо события, и затем снова приостановил работу. У этого есть обратная сторона введения задержки. Лучший трюк, когда это применимо, состоит в том, чтобы операционная система выполняла эти проверки как часть своих обычных операций, а затем пробуждала основной цикл вашего приложения, когда происходило что-то интересное. В Linux это делается с помощью системного вызова select, но select имеет ограничение, заключающееся в том, что он может указывать только ресурс, который может быть связан с дескриптором файла, поэтому устройства, стандартный ввод, файлы, сетевые порты в порядке.
Редактировать: Чтобы уточнить для моих downvoters: я не отрицаю существование аппаратных прерываний. Да, в тех случаях, когда код имеет прямой доступ к аппаратным прерываниям для всех событий, которые он хочет обработать (например, встроенная система или драйвер устройства), вы можете написать действительно «управляемый событиями» код с несколькими точками входа, который не занят ожиданием или спящим режимом. . Однако в обычной программе C уровня приложения, работающей под Linux, эта архитектура кода буквально не существует, а эмулируется на уровне приложения. Любое приложение Linux будет иметь основной цикл и по крайней мере один поток выполнения. Этот поток может быть приостановлен планировщиком, но он всегда существует и всегда имеет указатель инструкции на конкретную инструкцию. Если код покидает main(), программа завершается. Код не имеет возможности вернуться из main и позже получить обратный вызов от ядра. Код имеет единую точку входа и должен вызывать различные обработчики событий вручную. За исключением драйвера устройства (или очень специфического системного кода, использующего сигналы), вы не можете заставить ядро или аппаратное обеспечение автоматически вызывать определенную функцию, если пользователь щелкнул определенный пункт меню, вместо этого ваш код работает, сам обнаруживает это событие, и вызывает правильный обработчик событий.
Вы можете сказать LabView: «Вызовите эту функцию, когда произойдет XX». В C вы сообщаете своему собственному коду отправки события «Вызовите эту функцию, когда произойдет XX».
Я пытаюсь сказать (плохо?), что архитектура платформы событий не является родной для приложения C/Linux. Он должен эмулироваться вашим кодом с помощью основного потока диспетчеризации, который создает видимость среды, управляемой событиями. Либо вы делаете это вручную, либо используете библиотеку событий, которая делает это за кулисами, чтобы создать видимость модели, управляемой событиями. LabView использует второй подход, так что кажется, что никакой код не выполняется, когда не происходит никаких событий, но на самом деле существует собственный код LabView C++, управляющий очередями событий. Это не означает, что он все время занят ожиданием, как я уже говорил, есть системные вызовы, такие как select и sleep, которые код может использовать для получения процессорного времени, когда ему нечего делать, но код не может просто прекратить выполнение.
Допустим, вы хотите написать программу, управляемую событиями, с двумя обработчиками событий. Тот, который вызывается каждые десять секунд, называется tick(), и тот, который вызывается каждый раз, когда нажимается клавиша, называется key(), и тот, который вызывается каждый раз, когда набирается слово «foobar», называется foobar(). Вы можете определить эти три обработчика событий, но, кроме того, вам нужен некоторый основной поток диспетчеризации, который в основном делает
while not quitting
If 10 seconds have elapsed, call tick()
If Key has been Pressed
call key()
add save the key to our key buffer
If buffer now contains "foobar" call foobar() and clear buffer
Wait()
Если все события, о которых вы заботитесь, являются событиями уровня системы или событиями уровня времени, вы можете Wait() просто сказать ядру «разбуди меня, когда произойдет одно из этих событий», поэтому мне не нужно «ожидание занято» , Но вы не можете просто сказать ядру «вызывать foobar() при нажатии кнопки foobar». У вас должен быть код диспетчеризации на уровне приложения, который эмулирует структуру событий. Ваша программа на C имеет только одну точку входа из ядра. для каждого потока выполнения.Если вы посмотрите на библиотеки, которые предоставляют модели диспетчеризации событий, такие как Qt, вы обнаружите, что они работают так же, как это.
person
bdk
schedule
11.03.2010