just 2 cents, the use of semaphore & mutexes is relevant in the context of multi-threaded (or multi-processing) apps.
for the lazy (maybe just me) people, sometimes we simply spin lock to get what we need.
inefficient - sure, but more commonly i insert a asm("wfi"), which is nearly the same as yield(). for single threaded mode, yield() does nothing.
and asm("wfi") simply waits for the next systick and sleeps. semaphore & mutexes would really help as the 'RT'-OS takes care of that and instead of running busy spin locks the thread just stop running and cpu timeslice is given to other threads.
imho again, event loop is simply a different way of thinking about the normal loop(), i found it sometimes useful to based around an event loop setup as one could think of say a task() that check for buttons/keys and insert those key/button presses as events in the event loop. the dispatcher then poll the event handlers passing the event as an argument. each event handler then evaluate the event e.g. the key press and decides if it needs to service it.
this is very much like gui programming in windows, java swing etc.
the use of a queue in this way has some advantages, for instance an interrupt service routine (handler) can be used to post that key/button to the queue. this can happen outside the event dispatcher loop. but that keypress would still be routed to a event handler handling the event in due course. and in addition, things are strictly sequential. Hence, synchronization isn't needed.
i'd guess it is also a reason java forbid use of threads in the event dispatcher thread as messing with threads reading from, writing to a same queue can instead cause a deadlock. the event queue and loop (dispatcher) forces serialization and sequential processing of events - in a most inefficient manner, but by just forcing that, there is less of a synchronization concern, a queue forces every event to be processed sequentially rather than possibly concurrently. this significantly simply various codes. less worries about synchronization deadlocks etc e.g. instead of spin lock for a keystroke, button press, simply wait to receive the event from the event dispatcher in the event handler