Использование «goto» для остановки задачи в C / freeRTOS - PullRequest
1 голос
/ 15 января 2020

Я использую задачу State Machine для управления потоком моей программы. Когда выбрано состояние (кроме STAND BY), конечный автомат запускает связанную задачу с функцией «xTaskNotifyGive», поскольку все другие задачи блокируются с помощью «ulTaskNotifyTake (pdTRUE, portMAX_DELAY);»

Во время При выполнении этих задач, связанных с состоянием, может возникнуть проблема, и задача, связанная с состоянием, должна быть остановлена. Для этого в задаче «Безопасность» установите флажок «ContinueTask». В задаче, связанной с состоянием, мы регулярно проверяем этот флаг. Если оно ложно, следующий код не будет выполнен.

На данный момент структура кода выглядит следующим образом:

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», но не смог определить, можно ли его использовать, так как некоторые люди не согласны по этому вопросу, не дав дополнительного объяснения, почему.

Ответы [ 4 ]

3 голосов
/ 15 января 2020

Не высказывая своего мнения об использовании ключевого слова "goto", я думаю, что вы можете достичь того же поведения и избежать цикломатику c сложности, используя этот код:

ContinueTaskInternally = ContinueTaskCopy();
if (ContinueTaskInternally)
{
    //some code
    //...
    ContinueTaskInternally = ContinueTaskCopy();
}
if (ContinueTaskInternally)
{
    //some code
    //...
    ContinueTaskInternally = ContinueTaskCopy();
}
if (ContinueTaskInternally)
{
    //some code
    //...
}
//code before exiting task
3 голосов
/ 15 января 2020

Для меня это хорошая ситуация, чтобы использовать логические логики короткого замыкания c.

То есть: если флаг когда-либо установлен в false, вторая часть выражения && не будет оцениваться. Функция ContinueTaskCopy() не будет запущена.

Пока флаг true, весь код будет выполняться.
Как только флаг false, он пропустит все, если и все операторы 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 голосов
/ 15 января 2020

Да. goto не рекомендуется, но в вашем случае это будет работать. Я просто хочу объяснить здесь, почему goto не рекомендуется:

1. Dynami c выделение памяти

Если вы выделяете память динамически (malloc в целом, GlobalAlloc на Windows и c.), Вы можете сделать код, подобный следующему:

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.

1 голос
/ 16 января 2020

В этом конкретном случае c я думаю, что goto просто подходит. Таким образом, вы получили наиболее четкое и эффективное решение. Как и во всем остальном, убедитесь, что вы понимаете инструменты, которые используете, чтобы избежать путаницы. И довольно легко напутать и неправильно использовать «goto».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...