【问题标题】:Using "goto" to stop a task in C/freeRTOS在 C/freeRTOS 中使用“goto”停止任务
【发布时间】:2020-01-15 15:39:30
【问题描述】:

我正在使用状态机任务来处理我的程序流程。 When a state is selected (other than STAND BY), the State Machine wake up the associated task with the “xTaskNotifyGive” function as all other tasks are locked by “ulTask​​NotifyTake( pdTRUE, portMAX_DELAY);”

在执行这些与状态相关的任务期间,可能会发生问题并且与状态相关的任务必须停止。为了做到这一点,一个安全任务设置一个标志“ContinueTask”。在状态相关的任务中,我们会定期检查这个标志。如果为false,后面的代码将不会被执行。

目前,代码结构如下:

ContinueTaskInternally = ContinueTaskCopy();
if (ContinueTaskInternally){
    //some code
}
ContinueTaskInternally = ContinueTaskCopy();
if (ContinueTaskInternally){
    //some code
}
...
ContinueTaskInternally = ContinueTaskCopy();
if (ContinueTaskInternally){
    //some code
}

问题是,如果我们第一次检查时设置了标志,它仍然会检查下一部分代码。

解决这个问题的方法是使用这样的级联 if/else 语句:

ContinueTaskInternally = ContinueTaskCopy();
if (ContinueTaskInternally){
    //code
}
else{
    ContinueTaskInternally = ContinueTaskCopy();
    if (ContinueTaskInternally){
        //code
    }
    else{
        ContinueTaskInternally = ContinueTaskCopy();
        if (ContinueTaskInternally){
            //code
        }
        else{
            ....
        }
    }
}

但是如果我们在任务中检查这个标志很多时间,缩进的数量会非常高,并且不可读。

我想知道在这种情况下是否可以使用“goto”语句,如下所示:

ContinueTaskInternally = ContinueTaskCopy();
if (ContinueTaskInternally) goto exitTask;
//some code

ContinueTaskInternally = ContinueTaskCopy();
if (ContinueTaskInternally) goto exitTask;
//some code
...

ContinueTaskInternally = ContinueTaskCopy();
if (ContinueTaskInternally) goto exitTask;
//some code

exitTask:
//code before exiting task

你怎么看?我对那些“goto”语句进行了一些研究,但我无法确定是否可以使用,因为有些人不同意这个主题,而没有给出额外的解释。

【问题讨论】:

  • 为什么不能考虑到另一个函数和return 而不是goto

标签: c goto freertos


【解决方案1】:

对我来说,这是使用short circuit boolean logic 的好时机。

也就是说:如果标志曾经设置为false&& 表达式的第二部分将不会被计算。函数ContinueTaskCopy() 将不会运行。

只要标志是true,所有代码都会运行。
一旦标志为false,它将跳过所有if语句和所有ContinueTaskCopy语句,直到函数结束。

这使您的代码看起来像:

bool ContinueTaskInterally = true;

ContinueTaskInternally = ContinueTaskInterally && ContinueTaskCopy();
if (ContinueTaskInternally){
    //some code
}
ContinueTaskInternally = ContinueTaskInterally && ContinueTaskCopy();
if (ContinueTaskInternally){
    //some code
}
...
ContinueTaskInternally = ContinueTaskInterally && ContinueTaskCopy();
if (ContinueTaskInternally){
    //some code
}

【讨论】:

    【解决方案2】:

    没有对“goto”关键字的用法发表我的意见,我认为您可以使用此代码实现相同的行为并避免圈复杂度:

    ContinueTaskInternally = ContinueTaskCopy();
    if (ContinueTaskInternally)
    {
        //some code
        //...
        ContinueTaskInternally = ContinueTaskCopy();
    }
    if (ContinueTaskInternally)
    {
        //some code
        //...
        ContinueTaskInternally = ContinueTaskCopy();
    }
    if (ContinueTaskInternally)
    {
        //some code
        //...
    }
    //code before exiting task
    

    【讨论】:

      【解决方案3】:

      是的。不推荐goto,但在您的情况下,它会起作用。我只是想在这里解释一下为什么不推荐goto

      1.动态内存分配

      如果您动态分配内存(一般为malloc,Windows 上为GlobalAlloc 等),您可以执行如下代码:

      int* something = (int*)malloc(sizeof(int));
      // do something
      if (condition) goto endProgram;
      free(something);
      endProgram:
      // "something" may haven't been freed
      

      所以something 将保持分配状态。

      2。了解未定义行为的代码和风险

      goto 会使您的代码可读性降低或非常不直接。让我们看看这个例子:

      if (condition) goto someLabel;
      if (anotherCondition) {
          someLabel:
          // code
          goto abc;
      }
      for (int i = 0; i < limit; ++i) {
          // some code
          abc:
          // other code
      }
      

      所以如果condition 为真,我们跳到第二个if...然后我们跳到for 的中间...一些代码可能尚未执行,包括将i 设置为0 所以这是未定义的行为...可以在没有 goto 的情况下重新考虑此代码。

      【讨论】:

        【解决方案4】:

        在这种特定情况下,我认为 goto 非常适合。通过这种方式,您得到了最清晰、最有效的解决方案。就像其他所有事情一样,请确保您了解您正在使用的工具,以避免弄得一团糟。而且很容易弄乱和误用“goto”。

        【讨论】:

          猜你喜欢
          • 2019-04-25
          • 1970-01-01
          • 1970-01-01
          • 2016-08-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-12-31
          相关资源
          最近更新 更多