Во второй части серии я подробно остановлюсь на межзадачном взаимодействии в RTOS. Если вы не читали первую часть, взгляните на нее, если хотите получить базовые знания об основах ОСРВ.



Пойдем в наш старый добрый ресторан. Итак, теперь есть три рабочих, которые должны заботиться о работах. Person1 заботится о покупке ингредиентов на местном рынке. Person2 готовит блюда (рис и пиццу). Person3 может иметь дело с клиентами и обслуживанием. На данный момент они работают самостоятельно. Одного человека не волнует работа другого. Он будет продолжать делать то, что должен делать. Но это может быть не так. Принеся предметы, Человек1 должен сообщить Человеку 2, что он купил эти вещи и хранит их на полках. Person2 необходимо информировать Person3 о том, что он готовил каждый день и сколько осталось. Таким образом, существует потребность в улучшенном механизме связи. Если Person1 не сообщил Person2 о своих обновлениях, Person2 может прекратить готовить и искать возможные обновления от Person1. Это может привести к тупику, как я объяснял в предыдущей статье. В противном случае, даже до того, как Person2 закончит подготовку, Person3 может пойти и обслужить клиентов с полуприготовленным рисом, и тогда клиенты могут больше никогда не приходить. Это может привести к состоянию гонки, как я объяснил в предыдущей статье.

Механизмы межзадачного взаимодействия

В FreeRTOS используется множество межзадачных механизмов.

  1. Уведомления о задачах
  2. Мьютекс
  3. Семафор
  4. Очередь
  5. EventGroups

Есть две основные причины, по которым нам нужно лучше общаться.

  1. Уведомлять различные задачи о контексте (информация, относящаяся к задаче) или предоставлять некоторые данные
  2. Для доступа к общим данным

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

Уведомления о задачах

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

Как вы можете видеть здесь, задача 3 сработает только тогда, когда задача 2 уведомит его. Person3 будет обслуживать только после того, как Person2 сообщит, что еда готова. Task3 имеет дескриптор задачи. Другие задачи могут использовать этот дескриптор для отправки уведомлений. Те, кто знает обработчик задач, могут даже приостановить выполнение task3 от дальнейшего выполнения.

Уведомление, отправленное задаче, будет оставаться отложенным до тех пор, пока оно не будет очищено задачей, вызывающей xTaskNotifyWait () или ulTaskNotifyTake (). Если задача уже находилась в состоянии «Заблокировано» и ожидала уведомления при поступлении уведомления, то задача будет автоматически удалена из состояния «Заблокировано» (разблокирована) и будет выполнена.

Здесь я покажу, как можно отправить несколько уведомлений с помощью уведомлений о задачах.

Используя разные биты 32-битного целого числа без знака (как определено в ESP-IDF), задачи могут отправлять несколько уведомлений. Задача, ожидающая таких уведомлений, может использовать оператор switch для получения уведомления. Итак, как только Person2 приготовит рис, он сообщит Person3, что рис доступен. Теперь Person3 может информировать клиентов о наличии риса и подавать их. То же самое и с пиццей.

Есть много различных параметров, которые важны, но поскольку я не собираюсь обсуждать каждый API, я оставлю это на ваше усмотрение, если вы заинтересованы. однако, если одной задаче необходимо отправить некоторые большие структурированные данные другой, следует использовать механизм очереди.

Мьютекс

Мьютекс означает взаимное исключение задач при доступе к общему ресурсу. Мьютекс может быть реализован как токен. Когда задача пытается получить доступ к ресурсу, совместно используемому с другим, она должна получить для этого токен. Это сделано для того, чтобы избежать состояния гонки. В этом случае использование токена, чтобы разрешить доступ к общим данным только задаче, имеющей токен, может без проблем. Это показывает структуру программы, в которой задача 1 и задача 2 хотят обратиться к общим данным (в данном случае просто достичь общей функции). На этот раз это скорее практический пример.

API xSemaphoreTake / Give используются для получения и выпуска токена. Сначала я позвонил в task2. Итак, как вы можете видеть, первая задача 2 получит общие функции и влажность печати. Как только task2 выполнит с этим, он снимет флаг. Теперь задача 1 может использовать указанную выше функцию, и пока задача 2 ждет, задача 1 использует ее дважды, потому что задача 2 ждет вдвое дольше, чем задача 1. Поскольку оба они сбрасывают флаги после выполнения задания, программа никогда не перейдет в состояние тупика.

На этом пока все. Надеюсь, вам понравилась эта статья. Очереди, семафоры и группы событий фактически используются по-разному для достижения вышеуказанных требований. Если вам интересно, я рекомендую прочитать некоторые руководства по API, чтобы узнать об этом. Как я объяснил в конце первой статьи, вы можете широко использовать RTOS для многих сложных программ. Когда требования довольно простые, подход супер-цикла работает нормально. Однако есть много других интересных вещей, таких как распределение памяти с использованием статической или динамической памяти, программные таймеры, API для отладки с использованием JTAG и многое другое.

Спасибо за чтение и следите за обновлениями !.