|
Realtime software sometimes involves handling serial interactions with
multiple entities. A request is sent to an entity to initiate an operation, its
response is awaited and then on receipt of response, another request is sent to
the next entity and this sequence continues until response has been received
from the last entity in the sequence. Further action can be initiated only
after response message has been received from the last entity.
Serial Wait
state pattern handles such scenarios. Serial Wait state pattern is simpler
to implement than Parallel Wait state pattern. Also, it is easier to isolate
faults and initiate corrective action in Serial Wait state pattern since at any
given time, request response handshake is being performed only with one entity.
The figure below shows a typical serial operation. Here A initiates a serial operation by sending a request to
B. When B responds back to A, request is sent to C. Similarly, when C responds
back to A, request is sent to D to perform the
operation and respond back to A.

Intent
The main intention here is to initiate similar activity on multiple entities
in serial. Since activities are initiated in serial, the time taken to
perform the task increases with the number of entities involved
in the interaction. When the number of entities involved is too large and the
operation is time intensive, Parallel Wait state pattern should be
preferred over Serial Wait state pattern.
Serial Wait state pattern is suitable for its simplicity in design only when
the number of entities involved is small. Also, if each interaction is resource
intensive, then Parallel Wait state pattern will lead to loading the system with
multiple interactions running in parallel. In such cases, Serial Wait state
pattern is a better option as it allows only one resource intensive operation to
be active at any given time.
Also Known As
- Sequence Action State Pattern
- Serial Interaction
Motivation
Main motivation to use Serial Wait State pattern is to have a better control
over operations with
multiple entities by allowing only one operation at a time. In such designs,
fault diagnosis is straightforward. However, such designs do not scale very well
with the increase in number of entities.
Applicability
The Serial Wait State pattern can be used wherever an operation needs
to be performed on multiple entities and each operation is resource intensive,
thus not suitable for parallel operation.
Serial operations are generally simpler to implement and debug than parallel
operations. Thus they are a first choice of designers. Parallel operation is
often viewed as an optimization that can be carried out for serial operations
that turn out to be time intensive.
Structure
This pattern consists of the following event handlers:
- Serial Message Sending Routine: This
routine sends message to the next entity and starts a timer to keep track of
its response. It reports successful completion of serial operation
after the serial response handler receives the response from the last
entity.
- Serial Response Handler: This
handler receives the response message and responds to serial message
sending routine to proceed further.
- Timeout Handler: When a response
message is not received and a timeout takes
place, the serial message sending routine calls this handler. Depending on requirement,
one of the following options may be chosen:
- Timeout handler retries by resending the command message to the entity that
timed out.
- The timed out entity is skipped and serial message sending routine is
informed to proceed further.
- As soon as a timeout takes place, serial message sending routine
reports an unsuccessful completion of serial operation.
Participants
The key participants in this pattern are the task sending the message to
multiple entities serially and the tasks on these entities that receive this command
message, perform the desired operation and send back the response message.
Collaboration
The state machine implementing the Serial Wait state pattern collaborates with
the tasks on the entities where some desired operation needs to be performed.
The state machine keeps a timer to keep track of each operation being performed
at each entity.
Consequences
Serial state pattern can result in triggering a state transition
corresponding to successful collection of response messages. If a timeout takes
place before the collection of response messages has been completed, a state
transition to an error handling state might be initiated.
Implementation
Implementing the Serial Wait State Pattern involves sending request
messages to one entity at a time and waiting for the response before moving on
to the next entity. The
implementation sequence is illustrated by the following example based on digital
trunk status response to an operator command.
In the Xenon switching system XEN
Configuration Manager (XCM) needs to initiate status check on all the digital
trunks controlled by the XEN. This is done by sending status check request message to
first digital trunk controller and waiting for its response.
Once the response is received, the status check request is sent to the next
digital trunk controller. Once the response is received from the last
digital trunk controller, XCM responds back to the operator.
- Serial Wait State is invoked to perform status check on the first digital
trunk in the XEN by sending a command message.
- A timer is initiated to wait
for the status response. The timer is stopped on receipt of the response.
- On receipt of the response from the first digital trunk controller, the
Serial Wait State proceeds by sending the status check request command
message to the next digital trunk controller.
- When the last digital trunk controller responds, the aggregate response can be sent
back to the operator.
Sample Code and Usage
Here is the sample code for the digital trunk status check example:
| Digital
Trunk Status Check Using the Serial Wait State Pattern |
class CPerformingStatusCheckState : public CState
{
// The digital trunk number on which status check is being performed
int m_nCurrentDigitalTrunk;
public:
// Handle Statua Check Command from OMC
void OnOperatorStatusCheckCommand(CStateMachine &m, const StatusCheckCommand* pMsg)
{
// Set the current digital trunk for which status check is being performed to zero
m_nCurrentDigitalTrunk = 0;
// Send out status check request to the first digital trunk
SendStatusCheckRequest(m);
}
// Send out the status check request
void SendStatusCheckRequest(CStateMachine &m)
{
DigitalTrunk* pTrunk = m.GetDigitalTrunk(m_nCurrentDigitalTrunk);
// Send the status check request to this digital trunk controller
m.SendStatusCheckRequest(pTrunk->GetTrunkId());
// Update Trunk State
pTrunk->SetState(AWAITING_STATUS);
// Starting a timer to keep track of response
StartTimer();
}
// Handle Status Response
void OnStatusResponse(CStateMachine& m, const StatusResponse* pMsg)
{
DigitalTrunk *pTrunk = m.GetDigitalTrunk(pMsg->GetTrunkId());
// Check if the response has been received from a valid terminal in a valid state
if (pTrunk->GetState() != AWAITING_STATUS)
{
// No response is awaited from this terminal, so ignore the response
return;
}
// Set the state for the digital trunk back to idle
pTrunk->SetState(IDLE);
StopTimer();
// Save the status response
m.m_Status[pMsg->GetTrunkId()] = pMsg->GetStatus();
// Proceed to the next digital trunk in the serial interaction
MoveToNextDigitalTrunk();
}
// Handle Timeout
virtual void OnTimeout(CStateMachine& m, const CTimeoutMsg* pMsg)
{
TRACE("Status Response Missed from %d Digital Trunks\n", m_nCurrentDigitalTrunk);
m.m_Status[pMsg->GetTrunkId()] = TIMED_OUT;
// Set the state for the digital trunk back to idle
pTrunk->SetState(IDLE);
// Proceed to the next digital trunk in the serial interaction
MoveToNextDigitalTrunk();
}
// Check if status check request needs to be sent for the next digital trunk
// If all digital trunks have been covered then send the cumulative response
// to the operator
void MoveToNextDigitalTrunk()
{
// Increment the digital trunk count for which status check request will be sent
m_nCurrentDigitalTrunk++;
// Check if status response from all the digital trunks has been received
if (m_nCurrentDigitalTrunk < m.m_nNumDigitalTrunks)
{
// Send the Status Check Request message for the next digital trunk
SendStatusCheckRequest(m);
}
else
{
// Now respond back with the status of all status responses
m.SendCollectedStatusResponse(m.m_Status);
// Going back to Idle State, as serial state operation has been completed
m.ChangeState(m.pIdleState);
}
}
};
|
Known Uses
This design pattern has been used in the following cases:
- Serial initialization of multiple modules during system initialization.
- Polling of multiple entities in sequence.
- Responding to an operator command requesting information about multiple
entities.
Related Patterns
|