Структура событий - это просто абстракция, которая скрывает от вас поток выполнения. Должен быть какой-то код, выполняющийся где-то на компьютере, который проверяет эти события и затем вызывает ваши обработчики событий. в C вы должны будете сами предоставить этот код («основной цикл» программы). Этот код будет проверять различные источники событий, которые вас интересуют, и вызывать функции вашего обработчика событий.
Затем возникает хитрость, заключающаяся в том, чтобы не допустить, чтобы этот основной цикл дико вращал процессор. Один простой трюк состоит в том, чтобы основной цикл находился в спящем режиме в течение определенного периода времени, а затем проверял, нужно ли обрабатывать какие-либо события, и затем снова спал. Это имеет обратную сторону введения задержки. Лучшим трюком, когда это применимо, является то, что операционная система выполняет эти проверки как часть своих обычных операций, а затем запускает основной цикл вашего приложения, когда происходит что-то интересное. В Linux это делается с помощью системного вызова «select», но у select есть ограничение: он может указывать только ресурс, который может быть связан с дескриптором файла, поэтому устройства, stdin, файлы, сетевые порты в порядке.
Редактировать: Чтобы уточнить для моих downvoters: я не отрицаю наличие аппаратных прерываний. Да, в случаях, когда код имеет прямой доступ к аппаратным прерываниям для всех событий, которые он хочет обработать (например, встроенная система или драйвер устройства), вы можете написать действительно «управляемый событиями» код с несколькими точками входа, которые не заняты ожиданием или сном , Однако в обычной программе уровня приложения C, работающей под Linux, эта архитектура кода не существует буквально, а эмулируется на уровне приложения. Любое приложение Linux будет иметь основной цикл и, по крайней мере, один поток выполнения. Этот поток может быть приостановлен планировщиком, но он всегда существует и всегда имеет указатель инструкции на конкретную инструкцию. Если код покидает main (), программа завершается. Для кода нет возможности вернуться из main и позже получить обратный вызов из ядра. Код имеет одну точку входа и должен вручную вызывать различные обработчики событий. За исключением драйвера устройства (или очень специфического системного кода, использующего сигналы), ядро или оборудование не могут автоматически вызывать определенную функцию, если пользователь щелкнул по определенному пункту меню, вместо этого ваш код работает, обнаруживает это событие, и вызывает правильный обработчик события.
Вы можете сказать LabView «Вызовите эту функцию, когда произойдет XX». В C вы говорите свой собственный код отправки события «Вызовите эту функцию, когда произойдет XX».
Что я пытаюсь сказать (плохо?), Так это то, что архитектура среды событий не является родной для приложений C / Linux. Он должен эмулироваться вашим кодом, имея основной поток диспетчеризации, который создает видимость управляемой событиями среды. Либо вы делаете это вручную, либо используете библиотеку событий, которая делает это негласно, чтобы создать видимость модели, управляемой событиями. LabView использует второй подход, поэтому кажется, что никакой код не выполняется, когда не происходит никаких событий, но на самом деле существует собственный код CView LabView, управляющий очередями событий. Это не означает, что он все время ждет, как я уже говорил, есть системные вызовы, такие как 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()
Если все события, которые вас волнуют, являются событиями системного уровня или событиями временного уровня, вы можете подождать () может просто сообщить ядру «разбудите меня, когда произойдет одна из этих вещей», поэтому мне не нужно » «Ожидание занято», но вы не можете просто сказать ядру «вызвать foobar (), когда« нажата кнопка foobar ». У вас должен быть код отправки уровня приложения, который эмулирует структуру события. У вашей программы на Си есть только одна точка входа из ядра для каждого потока выполнения. Если вы посмотрите на библиотеки, которые предоставляют модели диспетчеризации событий, такие как Qt, то обнаружите, что они работают так же под капотом.