1. Architectural Patterns
[PART 4]
(Concurrency Pattern)
Based on
Pattern-Oriented Software Architecture, Patterns for Concurrent and
Networked Objects, Volume 2
by Douglas Schmidt, Michael Stal, Hans Rohnert and Frank Buschmann
2. Active Object
It decouples method execution from method invocation to enhance concurrency and simplify
synchronized access to objects that reside in their own thread of control.
Components –
Proxy – Resides in client thread . It provides an interface that allows clients to invoke publicly
accessible methods on an active object.
Client – It invokes public methods provided by proxy which in turn creates method request
object . when client invokes a method on a proxy, it receives a future. Each future reserves space
for the invoked method to store its result. The future allows the client to obtain the result of the
method invocation after the servant finishes executing the method.
Method Request object - It provides an interface for executing the methods of an active object.
This interface also contains guard methods that can be used to determine when a method
request can be executed
Activation list – proxy updated the list to keep track of pending method requests created by the
proxy and which method requests can execute.
Scheduler - It runs in the active object's thread. It decides which method request to execute next
on an active object. It scheduler uses the activation list to manage method requests that are
pending execution.
Servant – It defines methods correspond to the interface of the proxy and method requests the
proxy creates. It may also contain other predicate methods that method requests can use to
implement their guards. The servant method is executed on the active object.
4. Half-Sync/Half-Async
This pattern decouples asynchronous and synchronous service processing in
concurrent systems without reducing efficiency.
Decompose services in the system into two layers (synchronous and
asynchronous) and add a queuing layer between them to mediate the
communication between services in the asynchronous and synchronous
layers.
Components:
Synchronous service layer - Services in this layer run in separate threads or
processes that can block while performing operations.(e.g. ftp, telnet)
Asynchronous service layer - Services in this layer performs lower-level
processing services and cannot block while performing operations. (e.g.
Hardware interrupts)
Queuing layer - It is responsible for notifying services in one layer when
messages are passed to them from the other layer.
5. Half-Sync/Half-Async
External event sources - Generate events that are received and processed by
the asynchronous service layer (e.g. end-user terminal, disk controllers)
Asynchronous interrupts strategy - when an event occurs on an external
event source, an interrupt notifies the handler associated with the event,
which then processes the event to completion.
Proactive I/O strategy - I/O operations are executed by an asynchronous
operation processor. When an asynchronous operation finishes, the
asynchronous operation processor generates a completion event. This event
is then dispatched to the handler associated with the event, which processes
the event to completion.
Services in the asynchronous and synchronous layers can exchange messages
via queuing layer. This queuing layer buffers messages so that synchronous
and asynchronous services can run concurrently.
Notification strategy - It may be required to notify a service in one layer when
messages addressed to it arrive from another layer.
6. Leader/Followers
This pattern provides an efficient concurrency model where multiple threads
take turns sharing a set of event sources in order to detect, demultiplex,
dispatch, and process service requests that occur on the event sources
A pool of threads shares a set of event sources efficiently by taking turns,
demultiplexing events that arrive on these event sources and synchronously
dispatching the events to application services that process them.
Components Handle set - It is a collection of handles that can be used to wait for one or
more events to occur on handles in the set. A handle set returns to its
caller when it is possible to initiate an operation on a handle in the set
without the operation blocking.
event handlers - They implement the hook method(s) responsible for
processing events received from a handle
7. Leader/Followers
Thread pool – Threads that take turns playing three roles.
Leader role - The leader thread waits for an event to occur on any handle in
the handle set. If there is no current leader thread available, the underlying
operating system can queue events internally until a leader thread is
available.
Follower role - After the leader thread has detected a new event, it uses the
thread pool to choose a follower thread to become the new leader.
Processing role - This thread concurrently demultiplexes the event it detected
to the event's associated handler and then dispatches the handler's hook
method to process the event. After the processing thread has run its event
handling to completion, it can rejoin the thread pool.
9. Thread-Specific Storage
This pattern allows multiple threads to use one 'logically global' access point
to retrieve an object that is local to a thread—called a 'threadspecific
object'—without incurring locking overhead for each access to the object.
Components thread-specific object - It is an instance of an object that can be accessed
only by a particular thread (e.g. errno)
key factory - Keys generated by the key factory are assigned from a single
range of values to ensure that each thread-specific object is 'logically' global.
thread-specific object set – it contains the collection of thread-specific
objects that are associated with a particular thread. (e.g. OS threads library
implements the thread-specific object set that contains the errno data)
thread-specific object proxy - It can be defined to enable clients to access a
specific type of thread-specific object.(e.g. errno is implemented as a
preprocessor macro that plays the role of the proxy )
Application threads are clients that use thread-specific object proxies to
access particular thread-specific objects that reside in thread-specific storage