如何在C++中实现自动机/状态机编程?

3

我在另一种编程语言中使用过它,它非常有用。

但是我找不到任何关于C++的信息。

举个例子,让我们看以下代码:

void change();

enum
{
    end = 0,
    gmx
}

int
    gExitType;

int main()
{
    gExitType = end;
    SetTimer(&change, 10000, 0);
    return 0;
}

void ApplicationExit()
{
    switch (gExitType)
    {
        case end:
            printf("This application was ended by the server");
        case gmx:
            printf("This application was ended by the timer");
    }
    ::exit(0);
}

void change()
{
    gExitType = gmx;
    ApplicationExit();
}

这有点像我们在C++中的做法,但是当使用状态机/自动机时,我可以在另一种语言中做出如下操作:

void change();

int main()
{
    state exitType:end;
    SetTimer(&change, 10000, 0);
    return 0;
}

void ApplicationExit() <exitType:end>
{
    printf("This application was ended by the server");
}

void ApplicationExit() <exitType:gmx>
{
    printf("This application ended by the timer");
}

void change()
{
    state exitType:gmx;
    ApplicationExit();
}

在我看来,这是一种非常优雅的方法来实现目标。那么我该如何在C++中实现呢?这段代码似乎不起作用(显然,因为我找不到任何与自动机相关的内容)。
为了澄清我的观点:
那么使用这种技术有什么好处呢?嗯,正如您可以清楚地看到的那样,代码更小;尽管我在第一个版本中添加了一个枚举以使示例更相似,但ApplicationExit函数明显更小。它也更加明确-您不需要在函数中使用大型switch语句来确定发生了什么,如果您想要,可以将不同的ApplicationExits放在不同的文件中以独立处理不同的代码集。它还使用较少的全局变量。
3个回答

3
有像Boost.statechart这样的C++库,专门提供编码状态机的丰富支持:
http://www.boost.org/doc/libs/1_54_0/libs/statechart/doc/tutorial.html 此外,一种非常优雅的编码某些类型状态机的方法是将它们定义为协程:
http://c2.com/cgi/wiki?CoRoutine
http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-to-state-machines/ 协程在C++中不受直接支持,但有两种可能的方法来实现它们:

1) 使用类似于实现Duff's设备的技术,详细解释在这里:
http://blog.think-async.com/search/label/coroutines
这与C#的迭代器工作方式非常相似,但一个限制是只能从协程调用栈中的最顶层函数中进行协程yield。然而,这种方法的优点是每个协程实例所需的内存非常少。

2) 为每个协程分配单独的堆栈和寄存器空间。
这本质上使得协程成为一个完整的执行线程,唯一的区别是用户对线程调度(也称为协作式多任务处理)负有全部责任。
boost提供了一个可移植的实现:
http://www.boost.org/doc/libs/1_54_0/libs/coroutine/doc/html/coroutine/intro.html


2

对于这个例子,你可以使用对象和多态来表示不同的状态。例如:

class StateObject
{
    public:
        virtual void action(void) = 0;
};

class EndedBy : public StateObject
{
    private:
        const char *const reason;

    public:
        EndedBy( const char *const reason_ ) : reason( reason_ ) { }
        virtual void action(void)
        {
            puts(reason);
        }
};

EndedBy EndedByServer("This application was ended by the server");
EndedBy EndedByTimer ("This application ended by the timer");

StateObject *state = &EndedByServer;

void change()
{
    state = &EndedByTimer;
}

void ApplicationExit()
{
    state->action();
    ::exit(0);
}

int main()
{
    SetTimer(&change, 10000, 0);

    // whatever stuff here... 
    // presumably eventually causes ApplicationExit() to get called before return 0;

    return 0;
}

话虽如此,这并不是很好的设计,也不是通常意义下的有限状态机。但是,它可以实现您的即时需求。
您可以查阅《状态模式》(一个参考链接:http://en.wikipedia.org/wiki/State_pattern),以了解更一般的模式处理方法。
然而,基本思想是每个状态都是某个公共“状态”类的子类,您可以使用多态性来确定每个状态所表示的不同操作和行为。然后,指向公共“state”基类的指针会跟踪您当前所处的状态。
状态对象可以是不同类型的,或者像我上面的例子一样,是不同配置方式的同一对象的不同实例,或者是混合体。

1
你可以使用模板值特化来处理int类型,从而实现你想要的功能。
(很抱歉我在平板电脑上,无法提供示例,我会在周日更新。)

到现在我明白了模板是如何工作的(一年前还不懂),所以这可能是我今天会做的方式 :) - Gizmo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接