Using C + + to implement a simple state machine model--an example

Source: Internet
Author: User
Tags assert

Generally speaking, "state machine" is a method to express the transformation logic of State transformation. Someone has discussed with me why not use the IfElse directly, but using the "state machine" to implement some logic, think that the use of "state machine" is a kind of dazzling technology performance. However, for large and complex logic changes and jumps, the use of IfElse will bring code difficult to read and other drawbacks. In fact, IfElse is also a state machine implementation of the way.

Before we had a strong connection between the business and the operating system, and we wanted to clearly describe the process of each sub-business in the whole business, we introduced the state machine description. However, the state machine was described using the If Else method, and the whole process was rather bloated and the reading was not clear enough. So I tried to introduce a third-party state hangar to refactor this business-like the state hangar in boost. But the use of the process to feel a lot of inconvenience, simply self-made to achieve a clear and elegant state machine model. (reprint please indicate CSDN blog for breaksoftware)

Before we write the model, we need to understand what a state machine is. I searched for a number of results on the search engine, but most of them were very scholarly. And the realization of a chatty, all-encompassing, put a universal and suitable state machine model is not my original intention. The state machine I designed has the following features: Single-threaded, shallow history. The single thread is that our state machine is running inside of one of the threads and is not disturbed by other threads in the outside world, so we don't have to worry about multithreaded programming at design time. Shallow history is a concept in the state machine, which refers to the last left state that records only the highest layer of composite state. If you do not know this feature, you can search for it first. In practice, this feature is still very useful.

Let's introduce myself to this state machine in a simple, possibly inappropriate case. Let's first design a scenario: Install the software to the user's computer and run it. This scenario can be split into the following logic:

    1. Detect whether the installation
    2. Download the installation package
    3. Unzip the installation package and install
    4. Run

The four logic is not complicated, we define it as the underlying state-a state that we do not care about for a period of time and internal execution logic. To make this logic a little bit more complicated, we designed the following requirements:

For cases where the software is not installed:

    • Download the install package from the a address after failure download from B address
    • Download the installation package from the B address after failure download from c address
    • Failed to view execution after downloading installation package from C address
    • Detects if the CPU is busy after a successful download
    • CPU busy continues to detect whether the CPU is busy
    • Perform decompression when the CPU is not busy
    • The decompression fails to download again. If the previous a address download, then this time from the B address download, if the previous download from the B address, this time from the C address download
    • After successful decompression execution
    • The run failure is re-downloaded. If the previous a address download, then this time from the B address download, if the previous download from the B address, this time from the C address download
    • Successful operation is considered successful execution
For cases where the software is installed:
    • Run failed, then uninstall, then go to the "not installed software" logic
    • Successful operation is considered successful execution

We represent them in a state diagram:


The "Download composite state" in the figure is a composite state with a shallow historical feature; The post-install run state is a set of state combinations that let a complex set of state transitions become a state. This way, if the combination is to be reused elsewhere, simply introduce the combined state name.

We look at how to design and write code from the perspective of the user of the model, and the templates and functions in the code can be ignored first, so we know how to use them first.

From which we can determine the following output conditions

/* conddefine.h*/#pragma once//Whether to install the # define Condition_exist "Condition_exist" #define Condition_noexist "Condition_ Noexist "//Download succeeded # define CONDITION_DOWNLOAD_SUC" CONDITION_DONWLOAD_SUC "#define CONDITION_DOWNLOAD_FAI" Condition_ Donwload_fai "//CPU Busy # Condition_busy" condition_busy "#define CONDITION_NOBUSY" condition_nobusy "//Decompression succeeded # Define CONIDTION_UNZIP_SUC "CONIDTION_UNZIP_SUC" #define CONDITION_UNZIP_FAI "Condition_unzip_fai"//Run succeeded # define Condition_run_suc "CONDITION_RUN_SUC" #define CONDITION_RUN_FAI "Condition_run_fai"//Installation succeeded # define Condition_ Install_suc "CONDITION_INSTALL_SUC" #define CONDITION_INSTALL_FAI "Condition_install_fai"

The entire state jump has the following base state

Base State Class
Detect whether the installation Csimplestate_checkexist
Download from a address Csimplestate_download_from_a
Download from B Address Csimplestate_download_from_b
Download from c address Csimplestate_download_from_c
Detecting CPU Usage Csimplestate_checkcpu
Extract Csimplestate_unzip
Installation Csimplestate_install
Unloading Csimplestate_uninstall
Successful execution Csimplestate_success
Execution failed Csimplestate_failed
Run Csimplestate_run
We take the "download from a address" example to see the underlying code for that status

#pragma once#include "AutoStateChart.h" #include "StoreMachine.h"//Introduce output macros # include "CondDefine.h"//Introduce Business base class # # " Business_random.h "Class Cmachine_download_run_app;     Pre-assert state machine class Csimplestate_download_from_a: Public    Autostatechart::cautostatechartbase<csimplestate_ Download_from_a, Cmachine_download_run_app, Cstoreofmachine>{public:    csimplestate_download_from_a (void) {} ;    ~csimplestate_download_from_a (void) {};p ublic:    void Entry () {    };    std::string Exit () {        return condition_download_suc;    };};
It can be found that the class is very simple. We just use the template to declare the good class (template parameters: Self, state machine class, storage Class), and implement entry and exit two functions on the line。 Let's look again at the downloaded composite State class

 #pragma once# Include "AutoStateChart.h" #include "StoreMachine.h"//import output macro # include "CondDefine.h"//Introduce sub-state # include "Simplestate_ Download_from_a.h "#include" simplestate_download_from_b.h "#include" simplestate_download_from_c.h "class CMachine_     Download_run_app; Pre-assert state machine class//This class will produce two output condition_donwload_suc, Condition_donwload_faiclass ccompositestate_download:public Autostatechart::ccompositestates<ccompositestate_download, Cmachine_download_run_app, CStoreofMachine>{    Public:ccompositestate_download (void) {};    ~ccompositestate_download (void) {};p Ublic:registerstateconvertbegin (csimplestate_download_from_a)    Registerstateconvert (Csimplestate_download_from_a, Condition_download_fai, Csimplestate_download_from_b)    Registerstateconvert (Csimplestate_download_from_b, Condition_download_fai, Csimplestate_download_from_c) Registerstateconvertend ()}; 
This class is also very simple, it corresponds to the diagram of the


Where the Registerstateconvertbegin macro specifies the starting state (State Class) of the composite state, Registerstateconvert specifies the state rollover logic (former state class, condition, post-state Class).

Let's look at the class of the combined state of "post-installation State"

#pragma once#include "AutoStateChart.h" #include "StoreMachine.h"//Introduce output macros # include "CondDefine.h"//Introduce sub-states # include " Compositestate_download.h "#include" simplestate_failed.h "#include" simplestate_checkcpu.h "#include" simplestate_ Unzip.h "#include" simplestate_install.h "#include" simplestate_run.h "#include" simplestate_uninstall.h "#include"     Simplestate_success.h "Class Cmachine_download_run_app; Pre-asserted state machine class Ccollectionstate_install_run:public Autostatechart::ccollectionstates<ccollectionstate_    Install_run, Cmachine_download_run_app, Cstoreofmachine>{public:ccollectionstate_install_run (void) {};    ~ccollectionstate_install_run (void) {};p Ublic:registerstateconvertbegin (ccompositestate_download)    Registerstateconvert (Ccompositestate_download, CONDITION_DOWNLOAD_SUC, CSIMPLESTATE_CHECKCPU) Registerstateconvert (Ccompositestate_download, Condition_download_fai, csimplestate_failed) REGISTERSTATECONVERT (   CSIMPLESTATE_CHECKCPU, Condition_busy, CSIMPLESTATE_CHECKCPU) Registerstateconvert (Csimplestate_checkcpu, Condition_nobusy, Csimplestate_unzip) REGISTERSTATECONVERT ( Csimplestate_unzip, Conidtion_unzip_suc, Csimplestate_install) Registerstateconvert (CSimpleState_Unzip, CONDITION_ Unzip_fai, Ccompositestate_download) Registerstateconvert (Csimplestate_install, CONDITION_INSTALL_SUC,    Csimplestate_run) Registerstateconvert (Csimplestate_install, Condition_install_fai, CCompositeState_Download) Registerstateconvert (Csimplestate_run, CONDITION_RUN_SUC, csimplestate_success) Registerstateconvert (CSimpleState _run, Condition_run_fai, Csimplestate_uninstall) Registerstateconvert (Csimplestate_uninstall, "", CCompositeState_ Download) Registerstateconvertend ()};
The class is also very simple to registerstateconvertbegin, Registerstateconvert, and registerstateconvertend three macros make up the entire state jump graph


Finally, let's look at the class of the state machine.

#pragma once#include "AutoStateChart.h" #include "StoreMachine.h"//Introduce output macros # include "CondDefine.h"//Introduce sub-states # include " Simplestate_checkexist.h "#include" collectionstate_install_run.h "#include" simplestate_run.h "#include" Simplestate_uninstall.h "#include" Simplestate_success.h "Class Cmachine_download_run_app:public AutoStateChart:: Cautostatechartmachine<cmachine_download_run_app, Cstoreofmachine>{public:cmachine_download_run_app (void)    {};    ~cmachine_download_run_app (void) {};p Ublic:registerstateconvertbegin (csimplestate_checkexist)    Registerstateconvert (Csimplestate_checkexist, Condition_noexist, Ccollectionstate_install_run) Registerstateconvert (Csimplestate_checkexist, Condition_exist, Csimplestate_run) Registerstateconvert ( Csimplestate_run, Condition_run_fai, Csimplestate_uninstall) Registerstateconvert (CSimpleState_Run, CONDITION_RUN_ SUC, csimplestate_success) Registerstateconvert (Csimplestate_uninstall, "", Ccollectionstate_install_run) REGISTERS TATEconvertend ()}; 
It also makes up the entire logical jump through three macros.

In the premise of the module independence, the state machine is more elegant and concise show the entire state of the process of jump. Of course, behind this concise is still a lot of hidden behind the secret. We'll cover its implementation in the next section.

We end up with the following code to get the entire state machine running:

    Boost::shared_ptr<cmachine_download_run_app> SPC = boost::make_shared<cmachine_download_run_app> ();    Spc->startmachine ();

Using C + + to implement a simple state machine model--an example

Related Article

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.