Используйте внешнюю функцию, чтобы получить мьютекс в задаче - PullRequest
2 голосов
/ 07 октября 2019

Мне было интересно, могу ли я использовать мьютекс в задаче, но вызывая внешнюю функцию. Вот мой код ниже:

void TakeMutexDelay50(SemaphoreHandle_t mutex)
{
    while(xSemaphoreTake(mutex, 10) == pdFALSE)
    {
        vTaskDelay(50);
    }
}

bool ContinueTaskCopy()
{
    TakeMutexDelay50(ContinueTask_mutex);
    bool Copy = ContinueTask;
    xSemaphoreGive(ContinueTask_mutex);
    return Copy;
}

По сути, моя задача вызывает функцию ContinueTaskCopy (). Это хорошая практика?

Ответы [ 2 ]

1 голос
/ 07 октября 2019

Приведенный выше код будет работать, но если вы ничего не делаете в цикле while для взятия мьютекса, вы можете просто установить тайм-аут на portMAX_DELAY и избегать всех переключений контекста каждые 50 тиков.

0 голосов
/ 12 октября 2019

Чтобы ответить на ваши сомнения - да, этот код будет работать. С технической точки зрения сам код RTOS на самом деле не заботится о функции, которая принимает или освобождает мьютекс, это задача, которая выполняет код, который имеет значение (или, более конкретно, контекст, поскольку мы также включаем прерывания).

Фактически, некоторое время назад (я полагаю, какой-то версии FreeRTOS 7) они ввели дополнительную проверку в функции освобождения мьютекса, которая сравнивает задачу освобождения мьютекса с задачей, которая содержит мьютекс. Если это не то же самое, на самом деле происходит сбой утверждения, которое фактически является бесконечным циклом, мешающим вашей задаче продолжать работу, чтобы вы могли заметить и устранить проблему (есть многочисленные комментарии вокруг утверждений, которые помогут вам диагностировать проблему). Это делается так, как мьютексы используются для защиты ресурсов - например, доступ к SD-карте, доступ к дисплею и т. П. - и взятие мьютекса из одной задачи и освобождение его от другой противоречит всей этой идее или, по крайней мере, указывает на вонючий код. Если вам нужно сделать что-то подобное, вы, вероятно, захотите использовать вместо этого семафор.

Теперь, что касается второй части вашего вопроса - является ли это хорошей практикой для этого - я бы сказал, что это зависит от того, какСложно сделать это, но в целом я считаю это сомнительным. В целом, код, работающий на мьютексе, выглядит примерно так:

if(xSemaphoreTake(mutex, waitTime) == pdTRUE)
{
  doResourceOperation();
  xSemaphoreGive(mutex);
}

Это просто, легко понять, потому что именно так большинство используют для написания такого кода. Это в значительной степени позволяет избежать целого класса проблем с этим мьютексом, которые могут возникнуть, если вы начнете усложнять получение и освобождение кода («Почему он не освобожден?», «Кто держит этот мьютекс?», «Я в тупике?»). ). Проблемы такого рода, как правило, трудно отлаживать, а иногда даже трудно исправить, поскольку это может потребовать перестановки некоторых частей кода.

Чтобы дать общий совет - сделайте его простым. Видеть некоторые странные вещи, происходящие вокруг мьютекса, часто означает, что там происходят некоторые сомнительные вещи. Возможны некоторые неприятные тупики или условия гонки. Как и в вашем примере, вместо того, чтобы пытаться использовать мьютекс каждые 50 мсек до тех пор, пока он не преуспеет, просто подождите вечно, указав portMAX_DELAY время задержки для xSemaphoreTake и поместите его в ту же функцию, которая использует ресурс и освобождает мьютекс.

...