使用 "goto" 停止 C/freeRTOS 中的任务

Using "goto" to stop a task in C/freeRTOS

我正在使用状态机任务来处理我的程序流。 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" 声明进行了一些研究,但我无法确定是否可以使用,因为有些人不同意这个问题,但没有给出额外的理由。

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

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

只要flag是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
}

在不对 "goto" 关键字的用法给出我的意见的情况下,我认为您可以使用以下代码实现相同的行为并避免圈复杂度:

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

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

1.动态内存分配

如果您动态分配内存(malloc 通常,GlobalAlloc 在 Windows 等),您可以执行如下代码:

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
}

所以我们跳到第二个if如果condition为真...那么我们跳到for的中间...有些代码可能还没有执行包括将 i 设置为 0,因此它是未定义的行为......可以在没有 goto.

的情况下重新考虑此代码

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