Common code for demonstration of possibilities of (non)blocking (a)synchronous
behavior, do() is the studied call.
Blocking and synchronous
Blocking and asynchronous
Nonblocking and synchronous
Nonblocking and asynchronous
Insights
Blocking means current threadexecution container cannot progress
with the routine’s code (considering the routine itself). Effectively it
may be a long computing subroutine call or being unscheduled(e.g. blocking
I/O).
Multithreading Mutliple execution containers are quite
orthogonal concept to blocking.
You may use other execution containers to achieve non-blocking behavior
even with time consuming subroutines.
e.g. use other thread for calculation, assign a
future to
receiver
Other execution containers help you to get rid of blocking-ness.
Note that with preemptive scheduling you must synchronize access to
shared data (receiver, queue).
Asynchronous APIs
I think there are following asynchronous APIs:
callbacks,
blocking wait calls,
polling
and message passing?.
Callbacks
Blocking wait calls
Polling
On the line marked with XXX, we assume uninterrupted flow in order to consequently work with a valid result. This may be achieved by non-preemptive scheduling or using condition variables.
Message passing
This approach requires some encapsulation of communication entities. FIXME it’s just a different view on previous approaches.
Events
Events form an intermediate link between caller and callee/sender and receiver.
It allows implementing both synchronous and asynchronous behavior.
Qt’s direct and queue connections (also sent and posted events).
It may also allow runtime (dis)connection of senders/receivers.
Generally we want to avoid blocking in receivers/callees as it blocks whole program or event loop (in async scenario).
Partial remedy is calling processEvents (or similar) from within the blocking call.
Events without loop (synchronous events)
Calling raise_event is synchronous and depending on the actual listeners, it may also be blocking.
Note that if a raised event raises another instance of itself it may lead to stack overflow.
Events with loop (asynchronous events)
Calling raise_event is asynchronous and typically non-blocking (for blocking call, one would perform the computation inside raise_event and store result to the queue, which would be later assigned during process_event call).
This approach brings another level of versatility since each execution container can have it’s own queue (access to which needs to be correctly synchronized).
Shown only modification to the code above (the rest is same).