Implementation of the State Machine

Source: Internet
Author: User
Implementation of the State Machine

Original link address: http://drdobbs.com/cpp/184401236? Pgno = 1

It is easy to implement a state machine, but it is not easy to implement a good state machine. Generally, the following implementation occurs when the state machine is implemented:Code:

Switch (State _)

Case
A:

Do_a ();

Case
B:

Do_ B ();

End Switch

This method is understandable when the number of states is small and the logic for changing between States is relatively simple, but it has the following Disadvantages:

L logic code is chaotic. For example, if status A is switched to status B, the code will become bloated and no longer intuitive if verification is required. Example:

Case:

If
(Current_state! = C)

Return
-1;

Else

Current_state
=;

Return
0;

Case ....:

....

L difficult to expand; most States are processed Similarly, while some special States need special processing. For example, additional data needs to be provided, for example, setting a State to suspend in a task, you need to pass a time to be suspended. This is similar to the GUI.ProgramEvent Notification interface in, such:

Handle_event (eventid Event _, long Ext ,...)

EXT can actually pass anything. For example, if the event dropopen triggers a file drag to the icon, you can pass in the address of the file path to open through Ext. This method is quite powerful, so we can fully learn from it when implementing the state machine.

Context:

Assume that a task is a state machine whose status changes.

L after a task is created, assume that the required resources are obtained and the task enters the ready status.

L The ready status can be run by the task queue,
Then the task enters the running state.

L The ready status can be suspended by suspend. During the suspension, you need to identify the suspension time.

L running status can be suspended

L The sushortded status can be run to bring the task into the running status.

L The running, ready, and sushortded statuses can all be directly entered into the ended status through cancel.

Question:

N reasonable switching between States

N facilitates expansion, the task status may increase, and the task trigger Time may change. The state machine must be able to quickly adapt to logical changes.

Solution:

The following solutions are discussed:

U design base class:

    • The first is the virtual class used to transmit extended data.

# Ifndef event_data_h

# Define event_data_h

Class eventdata

{

Public:


Virtual ~ Eventdata (){};


Void * Data () = 0;

};

# Endif // event_data_h

    • Statemachine
      This class not only defines the interface, but also specifies the template for implementing the state machine. any implementation of the state machine can follow this template step by step.

# Ifndef state_machine_h

# Define state_machine_h

# Include <stdio. h>

# Include "eventdata. H"

Struct statestruct;

// Base class for state machines

Class statemachine

{

Public:


Statemachine (INT maxstates );


Virtual ~ Statemachine (){}

Protected:


Enum {event_ignored = 0xfe, cannot_happen };

Unsigned
Char currentstate;


Void externalevent (unsigned char, eventdata * = NULL );


Void internalevent (unsigned char, eventdata * = NULL );


Virtual const statestruct * getstatemap () = 0;

PRIVATE:


Const int _ maxstates;


Bool _ eventgenerated;


Eventdata * _ peventdata;


Void stateengine (void );

};

Typedef void
(Statemachine: * statefunc) (eventdata *);

Struct statestruct

{


Statefunc pstatefunc;

};

# Define begin_state_map \

Public :\

Const statestruct * getstatemap (){\


Static const statestruct statemap [] = {

# Define state_map_entry (entry )\

{
Reinterpret_cast <statefunc> (entry )},

# Define end_state_map \

{
Reinterpret_cast <statefunc> (null )}\


};\


Return & statemap [0];}

# Define begin_transition_map \


Static const unsigned char transitions [] = {\

# Define transition_map_entry (entry )\


Entry,

# Define end_transition_map (data )\

0
};\


Externalevent (transitions [currentstate], data );

# Endif // state_machine_h

Externalevent interface is an interface with validity verification. It first judges the validity of the status. If it is valid, internalevent is called,
Internalevent is an internal interface without verification, and it directly modifies the status.

    • Statemachine implementation; this implementation is a general logical template, any state machine implementation can apply this template.

# Include <assert. h>

# Include "statemachine. H"

Statemachine: statemachine (INT maxstates ):


_ Maxstates (maxstates ),


Currentstate (0 ),


_ Eventgenerated (false ),


_ Peventdata (null)

{

}

// Generates an external event. Called once
Per external event

// To start the state machine executing

Void statemachine: externalevent (unsigned
Char newstate,

Eventdata *
Pdata)

{


// If we are supposed to ignore this event


If (newstate = event_ignored ){

// Just delete the event data, if any


If (pdata)


Delete pdata;

}


Else if (newstate = cannot_happen ){


//! Throw exception ("XXX ");


//! Or


//! Logerror ("....");

}


Else {


// Generate the event and execute the state engine


Internalevent (newstate, pdata );


Stateengine ();

}

}

// Generates an internal event. Called from
Within a state

// Function to transition to a new state

Void statemachine: internalevent (unsigned
Char newstate,

Eventdata *
Pdata)

{


_ Peventdata = pdata;


_ Eventgenerated = true;


Currentstate = newstate;

}

// The state engine executes the state
Machine states

Void statemachine: stateengine (void)

{


Eventdata * pdatatemp = NULL;


If (_ eventgenerated ){


Pdatatemp = _ peventdata; // copy
Of Event Data Pointer


_ Peventdata = NULL; // event
Data used up, reset PTR


_ Eventgenerated = false; // event
Used up, reset flag


Assert (currentstate <_ maxstates );


// Execute the state passing in event data, if any


Const statestruct * pstatemap = getstatemap ();


(This-> * pstatemap [currentstate]. pstatefunc) (pdatatemp );


// If event data was used, then delete it


If (pdatatemp ){


Delete pdatatemp;


Pdatatemp = NULL;


}

}

}

Externalevent checks whether the status is valid. If it is event_ignored, ignore this operation directly. If it is cannot_happen, a logical error occurs.

L the implementation of specific tasks is as follows:

# Ifndef task_h

# Define task_h

# Include "statemachine. H"

Struct taskdata: Public eventdata

{


Int xxx;

};

Class task: Public statemachine

{

Public:


Task (): statemachine (st_max_states ){}


// External events taken by this State Machine


Void suspend ();


Void run ();


Void cancel ();

PRIVATE:


// State machine state functions


Void st_ready ();


Void st_running ();


Void st_suincluded (taskdata * pdata );


Void st_ended ();


// State map to define State function order


Begin_state_map


State_map_entry (st_ready)


State_map_entry (st_running)


State_map_entry (st_suincluded)


State_map_entry (st_ended)


End_state_map


// State enumeration order must match the order of State


// Method entries in the state map


Enum e_states {


St_ready = 0,


St_running,


St_suincluded,


St_ended,


St_max_states


};

};

# Endif // motor_h

Begin_state_map macro registers the custom state function to statemap, so that the corresponding state function can be obtained through the state value index.

L task implementation code

# Include <assert. h>

# Include "task. H"

Void task: suspend (motordata * pdata)

{


Begin_transition_map
//-Current state-


Transition_map_entry (st_susponded)
// St_ready


Transition_map_entry (st_susponded)
// St_running


Transition_map_entry (event_ignored)
// St_susponded


Transition_map_entry (cannot_happen)
// St_ended


End_transition_map (pdata)

}

Void task: Run (void)

{


Begin_transition_map
//-Current state-


Transition_map_entry (st_running)
// St_ready


Transition_map_entry (event_ignored)
// St_running


Transition_map_entry (st_running)
// St_susponded


Transition_map_entry (cannot_happen)
// St_ended


End_transition_map (null)

}

Void task: Cancel (void)

{


Begin_transition_map
//-Current state-


Transition_map_entry (st_ended)
// St_ready


Transition_map_entry (st_ended)
// St_running


Transition_map_entry (st_ended)
// St_susponded


Transition_map_entry (event_ignored) // st_ended


End_transition_map (null)

}

Void task: st_ready ()

{


Internalevent (st_ready );

}

Void task: st_running ()

{


Internalevent (st_running );

}

Void task: st_suincluded (motordata * pdata)

{


Internalevent (st_suincluded, pdata );

}

Void task: st_ended ()

{


Internalevent (st_ended );

}

In terms of status processing, the State is either valid, negligible, or not occurring at all.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.