65

I'm trying to understand what an event loop is. Often the explanation is that in an event loop, you do something until you're notified that an event has occurred. You then handle the event and continue doing what you were doing before.

To map the above definition with an example. I have a server which 'listens' in a event loop, and when a socket connection is detected, the data from it gets read and displayed, after which the server resumes/starts listening as it did before.


However, this event happening and us getting notified 'just like that' are to much for me to handle. You can say: "It's not 'just like that' you have to register an event listener". But what's an event listener but a function which for some reason isn't returning. Is it in it's own loop, waiting to be notified when an event happens? Should the event listener also register an event listener? Where does it end?


Events are a nice abstraction to work with, however just an abstraction. I believe that in the end, polling is unavoidable. Perhaps we are not doing it in our code, but the lower levels (the programming language implementation or the OS) are doing it for us.

It basically comes down to the following pseudo code which is running somewhere low enough so it doesn't result in busy waiting:

while(True):
    do stuff
    check if event has happened (poll)
    do other stuff

This is my understanding of the whole idea, and I would like to hear if this is correct. I'm open in accepting that the whole idea is fundamentally wrong, in which case I would like the correct explanation.

5
  • 3
    Event systems are implementations of the Observer pattern. Understanding the pattern should cement your understanding of events. No polling is required. Oct 18, 2013 at 20:21
  • 1
    Ultimately yes, even if language constructs abstract it away. Oct 18, 2013 at 20:30
  • @SteveEvers In your wiki link. What is the EventSource doing if not polling the keyboard input? Oct 18, 2013 at 20:36
  • @Alan: It could be doing anything, but for keyboard input specifically there do exist APIs to register your application as listening to keyboard events, which you can then use as your eventsource with no polling involved. Of course, if you go down far enough, USB is always polling, but let's assume we're using a PS/2 keyboard, which is interrupt driven, and then you have a keyboard input stack based on events with zero polling.
    – Phoshi
    Oct 25, 2013 at 8:25
  • I've had this questions since years, but I can't tell why I never bothered to ask it. Thanks, I am now satisfied with the understanding @Karl Bielefeldt has enlightened me with.
    – 0xc0de
    Dec 2, 2018 at 5:03

6 Answers 6

63

Most event loops will suspend if there are no events ready, which means the operating system will not give the task any execution time until an event happens.

Say the event is a key being pressed. You might ask if there's a loop somewhere in the operating system checking for keypresses. The answer is no. Keys being pressed generate an interrupt, which is handled asynchronously by the hardware. Likewise for timers, mouse movements, a packet arriving, etc.

In fact, for most operating systems, polling for events is the abstraction. The hardware and OS handle events asynchronously and put them in a queue that can be polled by applications. You only really see true polling at the hardware level in embedded systems, and even there not always.

11
  • 4
    Isn't an interrupt a change of voltage on a wire? Can that trigger an event by itself or must we poll the pin for the voltage value? Oct 18, 2013 at 20:47
  • 8
    That can trigger an event by itself. The processor is designed that way. In fact a processor can be woken up from sleep by an interrupt. Oct 18, 2013 at 20:50
  • 2
    I am confused with the statement Most event loops will block. How does this fit into the "the event loop paradigm, opposed to using threads, uses nonblocking asynchronous calls"? Oct 18, 2013 at 20:58
  • 1
    If you look at event loops for a library like GTK+, they check for new events then call event handlers in a loop, but if there aren't any events, they block on a semaphore or a timer or something. Individual developers make their own event loops that don't block on an empty event queue, but the widely-used libraries all block. Event loops are too inefficient otherwise. Oct 18, 2013 at 21:07
  • 1
    I suppose you could look at it that way, but it's multi threading in the library and/or OS rather than the application code. Event loops abstract the synchronization problems away for the application developer. Oct 18, 2013 at 21:29
14

I think of an event listener not as a function running its own loop, but as a relay race with the first runner waiting for the starting gun. A significant reason for using events instead of polling is that they are more efficient with CPU cycles. Why? Look at it from the hardware up (rather than the source code down).

Consider a Web server. When your server calls listen() and blocks, your code is taking its place as a relay runner. When the first packet of a new connection arrives, the network card starts the race by interrupting the operating system. The OS runs an interrupt service routine (ISR) that grabs the packet. The ISR passes the baton to a higher-level routine that establishes the connection. Once the connection is alive, that routine passes the baton to listen(), which passes the baton up to your code. At that point, you can do what you want with the connection. For all we know, between races each relay runner could be going to the pub. A strength of the event abstraction is that your code doesn't have to know or care.

Some operating systems include event-handling code that runs its portion of the race, hands off the baton, then loops back to its starting point to wait for the next race to start. In that sense, event handling is optimized polling in lots of concurrent loops. However, there is always an outside trigger that kicks off the process. The event listener is not a function that isn't returning, but a function that is waiting for that external trigger before it runs. Rather than:

while(True):
    do stuff
    check if event has happened (poll)
    do other stuff

I think of this as:

on(some event):    //I got the baton
     do stuff
     signal the next level up    //Pass the baton

and between the signal and the next time the handler runs, there is conceptually no code running or looping.

3
  • This makes sense, however what is the event loop doing while it's waiting for the interrupt? If it's blocking, isn't that the 'multi threaded' approach which is the paradigm opposite to the event loop? Oct 18, 2013 at 21:04
  • If your code has the loop forever: { select(); do stuff; } then you are re-entering the race every time through the loop. Whether you do that repeatedly from a single thread or in parallel on separate threads or processors, I think of each event as its own race. For example, a Web browser is a multithreaded program with multiple event loops in separate threads, at least one for the UI and one for each page it's downloading. The question I ask when coding is "how can I process events fast enough?" Sometimes the answer is a loop, sometimes threads, often a combination.
    – cxw
    Oct 18, 2013 at 22:02
  • I've been doing event-based programming for more than a couple decades, and I found this answer to be very confusing. For a listener to work, there must be a loop that waits for an event, then routes it to all of the registered listeners. (Assuming we're talking about software rather than hardware interrupts) Oct 18, 2013 at 23:30
9

I am going to go against all of the other answers I see so far and say "yes". I think the other answers are complicating things too much. From a conceptual point of view, all event loops are essentially:

while <the_program_is_running> {
    event=wait_for_next_event()
    process_event(event)
}

If you are trying to understand event loops for the first time, thinking of them as a simple loop will do no harm. Some underlying framework is waiting for the OS to deliver an event, it then routes the event to one or more handlers, then waits for the next event, and so on. That's really all there is to it from an application software perspective.

2
  • 1
    +1 for being straightforward. But the emphasis is on the "wait"; execution of this code will STOP on the first line of the loop and not continue until an event occurs. This is different than a busy polling loop that is repeatedly checks for an event until one occurs. Oct 23, 2013 at 2:14
  • I asked a similar question here stackoverflow.com/questions/68345852/…, with your help I did indeed confirm it is a while loop. Jul 13, 2021 at 2:55
9

No. It is not "optimized polling." An event-loop uses interrupt-driven I/O instead of polling.

While, Until, For, etc. loops are polling loops.

"Polling" is the process of repeatedly checking something. Since the loop code executes continuously, and because it is a small, "tight" loop, there is little time for the processor to switch tasks and do anything else. Almost all "hangs," "freezes," "lockups" or whatever you want to call it when the computer becomes unresponsive, are the manifestation of code being stuck in an unintended polling loop. Instrumentation will show 100% CPU usage.

Interrupt-driven event loops are far more efficient than polling loops. Polling is an extremely wasteful use of CPU cycles so every effort is made to eliminate or minimize it.

However, to optimize code quality, most languages try to use the polling loop paradigm as closely as possible for event handing commands since they serve functionally similar purposes within a program. Thus, with polling being the more familiar way to wait for a keypress or something, it is easy for the inexperienced to use it and wind up with a program that may run fine by itself, but nothing else works while it's running. It has "taken over" the machine.

As explained in other answers, in interrupt-driven event handing, essentially a "flag" is set within the CPU and the process is "suspended" (not allowed to run) until that flag is changed by some other process (such as the keyboard driver changing it when the user has pressed a key). If the flag is an actual hardware condition such as a line being "pulled high," it's called an "interrupt" or "hardware interrupt." Most however, are implemented as just a memory address on the CPU or in main memory (RAM) and are called "semaphores."

Semaphores can be changed under software control and so can provide a very fast, simple signalling mechanism between software processes.

Interrupts, however, can only be changed by hardware. The most ubiquitous use of interrupts is the one triggered at regular intervals by the internal clock chip. One of the countless kinds of software actions activated by clock interrupts, is the changing of semaphores.

I've left out a lot but had to stop somewhere. Please ask if you need more details.

8

Typically the answer is hardware, the OS and background threads you don't control conspire to make it look effortless. The network card receives some data it raises an interrupt to let the CPU know. The OS's interrupt handler handles it. Then a background thread you don't control (that was created by registering for the event and has been sleeping ever since you registered for the event) is woken up by the OS as part of handling the event and runs your event handler.

1

Not all events triggers are handled in loops. The way I often write my own event engines would be like this:

interface Listener {
    void handle (EventInfo info);
}

List<Listener> registeredListeners

void triggerEvent (EventInfo info) {
    foreach (listener in registeredListeners) { // Memo 1
        listener.handle(info) // the handling may or may not be synchronous... your choice
    }
}

void somethingThatTriggersAnEvent () {
    blah
    blah
    blah
    triggerEvent(someGeneratedEventInfo)
    more blah
}

Note that although Memo 1 is on a loop, the loop is for notifying each listener. The event trigger itself is not necessarily in a loop.

In theory, OS-level key events can use the same technique (though I think they often do polling instead? I'm just speculating here), provided the OS exposes some sort of registerListener API.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.