Or at least multithreaded. I was prototyping some vaguely image-related ideas in Processing, and decided that I wanted to pick which image file I was going to mess with on the fly rather than hard-coding the filename and path into the program. Down the rabbit hole I went.
Processing has a function for using your operating system’s select-a-file dialog. But because of the way that I/O is handled, it can’t just return a value containing/pointing to the file you selected. You have to specify a callback that — oh, wait, the callback can’t return a value either, it has to modify a previously-defined global variable. (The Processing language reference conveniently sidesteps this twist by providing an example that simply prints the selected file name to the console.)
So I put the file-selection magic in the setup function for my code, which runs before the main loop. The main loop ran, and then the selection dialog popped up. Huh? Oh, right, multithreading. The code in setup() returns as soon as it’s told the operating system what it wants and what callback to trigger. The fact that nothing substantive has been accomplished yet is irrelevant.
I have to admit to feeling just a tiny bit like a real programmer when I added a semaphore to the file-selection callback and the main loop. Now the main loop spins cheerfully at 30 frames a second doing nothing until I pick a file. Oh, and I want an output file too. Good thing my code doesn’t actually do anything.