【问题标题】:Switching behaviour (state) without too much runtime effort无需太多运行时工作即可切换行为(状态)
【发布时间】:2013-11-25 12:31:43
【问题描述】:

假设我有一个看起来像这样的有限状态机:

while(1){
    swtich(case){
        case ONE:
            do_thingone();
            if(parameter1 == 0)
                case = TWO;
        break;
        case TWO:
            do_thingtwo();
            do_thingthree();
            if(parameter1 == 1)
                case = ONE;
            if(parameter0 == 0)
                case = THREE;
        break;
//and so on
    }
}

使用布尔参数 p_master,我想在两个具有相似但不同内容的有限状态机之间进行切换。

while(1){
    switch(state){
        state STATE_0:
            switch(case){
                case ONE:
                    do_onething();
                    if(parameter1 == 0)
                        case = TWO;
                break;
              //case TWO:
            }
        break;

        case STATE_1:
            switch(case){
                case ONE:
                    do_anotherthing();
                    if(parameter1 == 0)
                        case = TWO;
                break;
              //case TWO:
            }
        break;
    }
}

我不想通过一个

检查和切换case
if(p_master == 0)

每次迭代反之亦然,因为我认为这会产生太多开销(p_master 仅每 100 次或 1000 次迭代更改一次,它甚至完全可以从不更改!)。有没有比有限状态机循环中的条件更优雅的方式来改变一个案例和另一个案例?
注意:p_master 可以作为 CPU 级别的中断触发!

【问题讨论】:

  • 为什么这会导致很多开销?这是一个简单的分支,如果它很少改变,应该很容易被分支预测器处理。
  • 提示:不要使用单词case 作为变量。它是一个保留字,即使它有效也可能引起混淆(例如:语法高亮)。
  • Nathan,它很少会改变,没错。但是我总是要检查它是否发生了变化,我想为这个检查找到一个更优雅的解决方案!

标签: c performance switch-statement interrupt


【解决方案1】:

switch 语句移动到函数中并调整函数指针。在 C 中实现有限状态机时,为每个状态(并且每个处理程序可以定义下一个处理程序)拥有一个专用的“处理程序”函数是很常见的。它也很好地映射到您可能会看到的状态机图(每个处理程序函数州)。

请参阅this question 以获得一些灵感。

【讨论】:

    【解决方案2】:

    函数指针。

    typedef void (*State_T) (void);
    
    void state_1(void);
    void state_2(void);
    
    void doStuff(void) {
        State_T currentState = state_1;
        while(...) {
            currentState();
        }
    }
    

    【讨论】:

      【解决方案3】:

      如果您只有几个这样的状态并且可以更改标志,为什么不将它们合并到一个开关中:

      switch(state | case){
          case STATE_0 | ONE:
              do_onething();
              if(parameter1 == 0)
                  case = TWO;
                  break;
          case STATE_0 | TWO:
              break;
          case STATE_1 | ONE:
              do_onething();
              if(parameter1 == 0)
                  case = TWO;
                  break;
          case STATE_1 | TWO:
              break;
      }
      

      【讨论】:

      • 谢谢,虽然这并不能解决我的实际问题,但很高兴知道可以这样做。我会记住的!
      猜你喜欢
      • 1970-01-01
      • 2017-01-03
      • 1970-01-01
      • 2023-03-25
      • 2021-05-12
      • 2018-05-07
      • 2017-09-04
      • 2012-02-19
      • 2018-04-22
      相关资源
      最近更新 更多