aboutsummaryrefslogtreecommitdiff
path: root/book/ru/src/by-example/tasks.md
diff options
context:
space:
mode:
Diffstat (limited to 'book/ru/src/by-example/tasks.md')
-rw-r--r--book/ru/src/by-example/tasks.md113
1 files changed, 83 insertions, 30 deletions
diff --git a/book/ru/src/by-example/tasks.md b/book/ru/src/by-example/tasks.md
index 3782804..3c99d00 100644
--- a/book/ru/src/by-example/tasks.md
+++ b/book/ru/src/by-example/tasks.md
@@ -1,22 +1,20 @@
# Программные задачи
-RTIC обрабатывает прерывания и исключения как *аппаратные* задачи. Аппаратные
-задачи могут вызываться устройством в ответ на события, такие как нажатие кнопки.
-RTIC также поддерживает *программные* задачи, порождаемые программой из любого
-контекста выполнения.
+В дополнение к аппаратным задачам, вызываемым в ответ на аппаратные события,
+RTIC также поддерживает *программные* задачи, которые могут порождаться
+приложением из любого контекста выполнения.
-Программным задачам также можно назначать приоритет и диспетчеризовать из
-обработчиков прерываний. RTIC требует определения свободных прерываний в блоке
-`extern`, когда используются программные задачи; эти свободные прерывания будут использованы, чтобы диспетчеризовать программные задачи. Преимущество программных
-задач перед аппаратными в том, что на один обработчик прерывания можно назначить
-множество задач.
+Программным задачам можно также назначать приоритет и, под капотом, они
+диспетчеризуются обработчиками прерываний. RTIC требует, чтобы свободные
+прерывания, были указаны в аргументе `dispatchers` модуля `app`, если используются
+программные задачи; часть из этих свободных прерываний будут использованы для
+управления программными задачами. Преимущество программных задач над аппаратными
+в том, что множество задач можно назначить на один обработчик прерывания.
-Программные задачи определяются заданием функциям атрибута `task`. Чтобы было
-возможно вызывать программные задачи, имя задачи нужно передать в аргументе
-`spawn` контекста атрибута (`init`, `idle`, `interrupt`, etc.).
+Программные задачи также определяются атрибутом `task`, но аргумент `binds` опускается.
-В примере ниже продемонстрированы три программных задачи, запускаемые на 2-х
-разных приоритетах. Трем задачам назначены 2 обработчика прерываний.
+Пример ниже демонстрирует три программные задачи, запускаемых 2-х разных приоритетах.
+Три программные задачи привязаны к 2-м обработчикам прерываний.
``` rust
{{#include ../../../../examples/task.rs}}
@@ -24,15 +22,16 @@ RTIC также поддерживает *программные* задачи,
``` console
$ cargo run --example task
-{{#include ../../../../ci/expected/task.run}}```
+{{#include ../../../../ci/expected/task.run}}
+```
## Передача сообщений
-Другое преимущество программных задач - возможность передавать сообщения задачам
-во время их вызова. Тип полезной нагрузки сообщения должен быть определен в
-сигнатуре обработчика задачи.
+Другое преимущество программной задачи в том, что задачам можно передать сообщения
+в момент их запуска. Тип передаваемого сообщения должен быть определен в сигнатуре
+задачи-обработчика.
-Пример ниже демонстрирует три задачи, две из которых ожидают сообщения.
+Пример ниже демонстрирует три задачи, две из которых ожидают сообщение.
``` rust
{{#include ../../../../examples/message.rs}}
@@ -40,19 +39,23 @@ $ cargo run --example task
``` console
$ cargo run --example message
-{{#include ../../../../ci/expected/message.run}}```
+{{#include ../../../../ci/expected/message.run}}
+```
-## Ёмкость
+## Вместимость
-Диспетчеры задач *не* используют динамическое выделение памяти. Память
-необходимая для размещения сообщений, резервируется статически. Фреймворк
-зарезервирует достаточно памяти для каждого контекста, чтобы можно было вызвать
-каждую задачу как минимум единожды. Это разумно по умолчанию, но
-"внутреннюю" ёмкость каждой задачи можно контролировать используя аргумент
-`capacity` атрибута `task`.
+RTIC *не* производит никакого рода аллокаций памяти в куче.
+Память, необходимая для размещения сообщения резервируется статически.
+По-умолчанию фреймворк минимизирует выделение памяти программой таким образом,
+что каждая задача имеет "вместимость" для сообщения равную 1:
+это значит, что не более одного сообщения можно передать задаче перед тем, как
+у нее появится возможность к запуску. Это значение по-умолчанию можно
+изменить для каждой задачи, используя аргумент `capacity`.
+Этот аргумент принимает положительное целое, которое определяет как много
+сообщений буфер сообщений задачи может хранить.
-В примере ниже установлена ёмкость программной задачи `foo` на 4. Если ёмкость
-не определена, тогда второй вызов `spawn.foo` в `UART0` вызовет ошибку.
+Пример ниже устанавливает вместимость программной задачи `foo` равной 4.
+Если вместимость не установить, второй вызов `spawn.foo` в `UART0` приведет к ошибке (панике).
``` rust
{{#include ../../../../examples/capacity.rs}}
@@ -60,4 +63,54 @@ $ cargo run --example message
``` console
$ cargo run --example capacity
-{{#include ../../../../ci/expected/capacity.run}}```
+{{#include ../../../../ci/expected/capacity.run}}
+```
+
+## Обработка ошибок
+
+Интерфейс `spawn` возвращает вариант `Err`, если для размещения сообщения нет места.
+В большинстве сценариев возникающие ошибки обрабатываются одним из двух способов:
+
+- Паника, с помощью `unwrap`, `expect`, и т.п. Этот метод используется, чтобы обнаружить
+ ошибку программиста (например bug) выбора вместительности, которая оказалась недостаточна.
+ Когда эта паника встречается во время тестирования, выбирается большая вместительность,
+ и перекомпиляция программы может решить проблему, но иногда достаточно окунуться глубже
+ и провести анализ времени выполнения программы, чтобы выяснить, может ли платформа
+ обрабатывать пиковые нагрузки, или процессор необходимо заменить на более быстрый.
+
+- Игнорирование результата. В программах реального времени, как и в обычных, может быть
+ нормальным иногда терять данные, или не получать ответ на некоторые события в пиковых ситуациях.
+ В таких сценариях может быть допустимо игнорирование ошибки вызова `spawn`.
+
+Следует отметить, что повторная попытка вызова `spawn` обычно неверный подход, поскольку
+такая операция на практике вероятно никогда не завершится успешно.
+Так как у нас есть только переключения контекста на задачи с *более высоким* приоритетом,
+повторение вызова `spawn` на задаче с низким приоритом никогда не позволит планировщику
+вызвать задачу, что значит, что буфер никогда не будет очищен. Такая ситуация отражена в
+следующем наброске:
+
+``` rust
+#[rtic::app(..)]
+mod app {
+ #[init(spawn = [foo, bar])]
+ fn init(cx: init::Context) {
+ cx.spawn.foo().unwrap();
+ cx.spawn.bar().unwrap();
+ }
+
+ #[task(priority = 2, spawn = [bar])]
+ fn foo(cx: foo::Context) {
+ // ..
+
+ // программа зависнет здесь
+ while cx.spawn.bar(payload).is_err() {
+ // повтор попытки вызова spawn, если произошла ошибка
+ }
+ }
+
+ #[task(priority = 1)]
+ fn bar(cx: bar::Context, payload: i32) {
+ // ..
+ }
+}
+```