Event handling and messages between parts of programs also in distributed systems are a fundamental concept of programming. This concept was already found in the 1960th by the developing of OOP ObjectOrientated Programming in Smalltalk. You may read some about this topics in https://www.researchgate.net/publication/221501755_The_Early_History_of_Smalltalk. It was written from Alan Kay (Wikipedia link).
In UML events are present of course in state machines, but also as basically idea for the sequence charts. The last one are often seen only as 'sequence of calling operations' but the arrows between the instance lines were originally events.
In currently software events are present for graphical programming. All actions of the user in a GUI (Graphical User Interface) are caused by events, mouse press events, key events etc.
The event handling is not present in the adequate way as basic for all programming languages, which should be originally expected by its early history starting with the 1960th. Event handling was temporary forgotten and avoided, or simple substituted by other concepts. But it is intrinsically a basic concept, should be present in all programming environments.
An 'event' is the occurrence of anything, which forces an action. In normal live an event is, when the alarm clock rings. The action is: get up, take breakfast, start working.
A 'message' is the transport form of an event. A letter contains a message. The post box is the message queue. The occurrence, you have a letter and your mother in law writes, you and your wife or husband should visit her, that is the event. The action is: Ignore her letter (one of the possible actions).
Events are associated to data, the message contains the data as payload.
Transfer of events or more exact messages are coupling between different objects. These objects can be freely or strongly coupled. A strong coupling is: The receiver of the message or the executer of the event is in the same programming environment. You can be inform about its state also outside of the event processing, get data immediately. If your mother in law lives in the same house, she is strongly coupled, you cannot escape from her. A freely coupling is, if the event is transferred to another device, which’s state is unknown. Also the connection may be disturbed. You can only send the event as negotiated, and hope of answer.
For example you have had a friend a longer time ago. You write him a message, hope for answer, but an answer does not come. Then, after a sufficient waiting time, you decide for a contact to another people.
Events, messages, respond, timeout, actions, it is all in computer programs as also in the normal life.
If the counterpart is another thread, it can be seen as freely (no other data from the other thread will be checked because care for data consistency) or more strongly.
It is an important facility, that the data which are transported with a message and which are associated to the event are only used with evaluation of the event. It should not used by another program part or any other with immediately access, it should be coupled only to the event.
For that reason the consistency of data are prevented by the message and event.
If you have two threads, data consistence is a topic. If you only couple the threads via events, the data consistence is met.
You can send some messages to different destinations in expecting, that the actions due to the events are executed. You can inform some destinations which can execute the actions independently, so a parallel execution is possible.
One event executed, then the next event in the same destination is evaluated. It means you define the order of execution of the actions due to the events.
If an action is executed, the action itself can force the event for the next action, either in the same thread and object, or in any other one. If it is in the same thread and object, you get a statement order.
The simplest form to send an event is: You have a destination for the event. The destination gets the event and the data in the same thread and can do actions. This is the same as an callback, if you give your routine the information about the destination.
event action in the same thread, similar as a callback
routine(evDst) other Object, the evDst | | +------>event with data----->- + executes the event action |<----resumes-----------------
The sceme above is similar a sequence diagram in UML.
event action in another thread in the same process
routine queue other thread | | | +----->event with data--------->stored | | | does any other stuff continues | | +-----(other) event with data-->stored | | |---get-->+ executes the event |
With an event queue you have a timing decoupling. You do not know when the event action is executed, you also don’t know whether the other thread will ever get events from the queue. This can only work proper if you have back events and maybe timeouts.
event action in another process or device
routine queue communi queue other | . cation . process +-->event1---->stored1 . . : | . . . does any other stuff continues . . . or waits for work +---event2---->stored2 . . : | |==>send msg=====>| : | . . stored1 : wait for . . stored2 : answer . . |----get->+ executes the event : . . . | : . . stored3<--ev-| sends the answer event : |<==send msg======| : : stored3 . . : |<--notified------| . . :
If the coupling is done to another process or device, you have any kind of interprocessCommunication. The communication can have its own time organization, it means it may communicate the events not immediately (assume, some events come in less microseconds), it communicates with its cycle, for example 10 ms. It can be proper to gather some more event entries for one communication action. On the other side the events are firstly stored also in a queue by the communication thread, and then distributed to the destination threads or event consumers. The way back is similar.
It means if the left routine should wait for an answer, it should be planned that the answer comes after a longer response time. The left routine respectively this thread may wait (release the CPU) and it is notified if an event comes, its action is processed in the destination and because the action is done, this routine is awaken (notified)
Events occurs with any trigger. The trigger can be for example
a human handling, for example press a button in a Graphical User Interface
a hardware event, for example a signal a line from a contact comes to high level
a communication occurence, a telegrams is received which contains messages.
a software controlled event from another thread or process or events (as result of processing event actions).
a cyclic event triggered from a hardware timer.
An interrupt in an embedded control can be seen also as such cyclical event. It is a quest of implementing whether you have a thread which waits for the cyclic event transmitted from the interrupt, or the interrupt is the event handling by itself, and of course it emits some other events to other threads, to the communication or what else.
Cyclic events means, also a cyclically task (for example a controller algorithm step opeation) can be forced by events.
Maybe you know the IEC61131, that is the automation control via latter diagrams, function block diagrams and more, in german may be known by the Siemens KOP FUP AWL or TIA portal (https://new.siemens.com/global/en/products/automation/industry-software/automation-software/tia-portal.html). This standard is present since about 1968, very long life, of course improved.
Now in the years starting from ~2006 a new development for this approaches was done, with similar features, standardized in IEC61499. The important new of this approach is: It is event based.
With the event based coupling of Function blocks it is very simple to designate, in which device any block is assigned. You can very more simple engineer an distributed automation system. Also the processing order is determined by the events.
If you have some Function Blocks in the same device, coupled proper with events, the result is similar as in IEC61131 FBD. The blocks are processed one after another. But you can better see the order of processing if your system is distributed in some more diagram pages.
If you have Function Blocks in another device between (because for example your signals come from another location in your real process), automatically a communication is organized by the implementation (after building the project). The communication planning and projecting in a IEC61131 automation plan is a higher effort. In IEC61499 it is done by the way.
Of course, the stability of technology may recommend furthermore usage of the well-known and proven standard 61131. But the IEC61499 norm is better. See for example
https://www.eclipse.org/4diac/: 4diac, an engineering tool for IEC61499
Events are very familiar in all GUI implementations, also in C or C++ (for example https://doc.qt.io/qt-6/eventsandfilters.html in QT graphic), and also for example in Java (for example in SWT: https://help.eclipse.org/latest/ntopic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/events/package-summary.html) and in all other GUI platforms.