aboutsummaryrefslogtreecommitdiff
path: root/book/ru/src/by-example/resources.md
diff options
context:
space:
mode:
Diffstat (limited to 'book/ru/src/by-example/resources.md')
-rw-r--r--book/ru/src/by-example/resources.md177
1 files changed, 102 insertions, 75 deletions
diff --git a/book/ru/src/by-example/resources.md b/book/ru/src/by-example/resources.md
index b53ef40..70f798d 100644
--- a/book/ru/src/by-example/resources.md
+++ b/book/ru/src/by-example/resources.md
@@ -1,22 +1,27 @@
-## Ресурсы
-
-Одно из ограничений атрибутов, предоставляемых библиотекой `cortex-m-rt` является
-то, что совместное использование данных (или периферии) между прерываниями,
-или прерыванием и функцией `init`, требуют `cortex_m::interrupt::Mutex`, который
-*всегда* требует отключения *всех* прерываний для доступа к данным. Отключение всех
-прерываний не всегда необходимо для безопасности памяти, но компилятор не имеет
-достаточно информации, чтобы оптимизировать доступ к разделяемым данным.
-
-Атрибут `app` имеет полную картину приложения, поэтому может оптимизировать доступ к
-`static`-переменным. В RTIC мы обращаемся к `static`-переменным, объявленным внутри
-псевдо-модуля `app` как к *ресурсам*. Чтобы получить доступ к ресурсу, контекст
-(`init`, `idle`, `interrupt` или `exception`) должен сначала определить
-аргумент `resources` в соответствующем атрибуте.
-
-В примере ниже два обработчика прерываний имеют доступ к одному и тому же ресурсу.
-Никакого `Mutex` в этом случае не требуется, потому что оба обработчика запускаются
-с одним приоритетом и никакого вытеснения быть не может.
-К ресурсу `SHARED` можно получить доступ только из этих двух прерываний.
+# Ресурсы
+
+Фреймворк предоставляет абстракцию для разделения данных между любыми контекстами,
+с которыми мы встречались в предыдущей главе (задачами-обработчиками, `init` и `idle`): ресурсы.
+
+Ресурсы - это данные, видимые только функциями, определенными внутри модуля `#[app]`.
+Фреймворк дает пользователю полный контроль за тем, какой контекст может
+получить доступ к какому ресурсу.
+
+Все ресурсы определены в одной структуре внутри модуля `#[app]`.
+Каждое поле структуры соответствует отдельному ресурсу.
+`struct`-ура должна быть аннотирована следующим атрибутом: `#[resources]`.
+
+Ресурсам могут быть опционально даны начальные значения с помощью атрибута `#[init]`.
+Ресурсы, которым не передано начально значение, называются
+*поздними* ресурсами, более детально они описаны в одном из разделов на этой странице.
+
+Каждый контекс (задача-обработчик, `init` или `idle`) должен указать ресурсы, к которым
+он намерен обращаться, в соответсятвующем ему атрибуте с метаданными, используя
+аргумент `resources`. Этот аргумент принимает список имен ресурсов в качестве значения.
+Перечисленные ресурсы становятся доступны в контексте через поле `resources` структуры `Context`.
+
+Пример программы, показанной ниже содержит два обработчика прерывания, которые разделяют
+доступ к ресурсу под названием `shared`.
``` rust
{{#include ../../../../examples/resource.rs}}
@@ -27,41 +32,36 @@ $ cargo run --example resource
{{#include ../../../../ci/expected/resource.run}}
```
-## Приоритеты
+Заметьте, что к ресурсу `shared` нельзя получить доступ из `idle`. Попытка сделать это
+приведет к ошибке компиляции.
-Приоритет каждого прерывания можно определить в атрибутах `interrupt` и `exception`.
-Невозможно установить приоритет любым другим способом, потому что рантайм
-забирает владение прерыванием `NVIC`; также невозможно изменить приоритет
-обработчика / задачи в рантайме. Благодаря этому ограничению у фреймворка
-есть знание о *статических* приоритетах всех обработчиков прерываний и исключений.
+## `lock`
-Прерывания и исключения могут иметь приоритеты в интервале `1..=(1 << NVIC_PRIO_BITS)`,
-где `NVIC_PRIO_BITS` - константа, определённая в библиотеке `device`.
-Задача `idle` имеет приоритет `0`, наименьший.
+Критические секции необходимы для разделения изменяемых данных таким образом,
+чтобы избежать гонок данных.
-Ресурсы, совместно используемые обработчиками, работающими на разных приоритетах,
-требуют критических секций для безопасности памяти. Фреймворк проверяет, что
-критические секции используются, но *только где необходимы*: например,
-критические секции не нужны для обработчика с наивысшим приоритетом, имеющим
-доступ к ресурсу.
+Поле `resources`, передаваемого `Context` реализует трейт [`Mutex`] для каждого разделяемого
+ресурса, доступного задаче.
-API критической секции, предоставляемое фреймворком RTIC (см. [`Mutex`]),
-основано на динамических приоритетах вместо отключения прерываний. Из этого следует,
-что критические секции не будут допускать *запуск некоторых* обработчиков,
-включая все соперничающие за ресурс, но будут позволять запуск обработчиков с
-большим приоритетом не соперничащих за ресурс.
+Единственный метод этого трейта, [`lock`], запускает свой аргумент-замыкание в критической секции.
[`Mutex`]: ../../../api/rtic/trait.Mutex.html
+[`lock`]: ../../../api/rtic/trait.Mutex.html#method.lock
-В примере ниже у нас есть 3 обработчика прерываний с приоритетами от одного
-до трех. Два обработчика с низким приоритетом соперничают за ресурс `SHARED`.
-Обработчик с низшим приоритетом должен заблокировать ([`lock`]) ресурс
-`SHARED`, чтобы получить доступ к его данным, в то время как обработчик со
-средним приоритетом может напрямую получать доступ к его данным. Обработчик
-с наивысшим приоритетом может свободно вытеснять критическую секцию,
-созданную обработчиком с низшим приоритетом.
+Критическая секция, создаваемая интерфейсом `lock` основана на динамических приоритетах:
+она временно повышает динамический приоритет контекста до *максимального* приоритета,
+что не дает другим задачам возможности вытеснить критическую секцию.
+Этот протокол синхронизации известен как [Протокол немедленного максимального приоритета
+(ICPP)][icpp], и компилируется диспетчером RTIC с [Политикой ресурсов стека(SRP)][srp].
-[`lock`]: ../../../api/rtic/trait.Mutex.html#method.lock
+[icpp]: https://en.wikipedia.org/wiki/Priority_ceiling_protocol
+[srp]: https://en.wikipedia.org/wiki/Stack_Resource_Policy
+
+В примере ниже у нас есть три обработчика прерываний с приоритетами от одного до трех.
+Два из обработчиков с более низким приоритетом соревнуются за ресурс `shared`,
+поэтому должны блокировать доступа к данным ресурса.
+Обработчик с наивысшим приоритетом, который не имеет доступа к ресурсу `shared`,
+может свободно вытеснять критическую секцию, созданную обработчиком с низким приоритетом.
``` rust
{{#include ../../../../examples/lock.rs}}
@@ -69,26 +69,32 @@ API критической секции, предоставляемое фрей
``` console
$ cargo run --example lock
-{{#include ../../../../ci/expected/lock.run}}```
+{{#include ../../../../ci/expected/lock.run}}
+```
+
+## Множественное блокировка
+
+Это расширение к `lock`, чтобы уменьшить количесво отступов, блокируемые ресурсы можно объединять в кортежи.
+Следующий пример это демонстрирует:
+
+``` rust
+{{#include ../../../../examples/multilock.rs}}
+```
## Поздние ресурсы
-В отличие от обычных `static`-переменных, к которым должно быть присвоено
-начальное значение, ресурсы можно инициализировать в рантайме.
-Мы называем ресурсы, инициализируемые в рантайме *поздними*. Поздние ресурсы
-полезны для *переноса* (как при передаче владения) периферии из `init` в
-обработчики прерываний и исключений.
+Поздние ресурсы - такие ресурсы, которым не передано начальное значение во время компиляции
+с помощью атрибута `#[init]`, но которые вместо этого инициализируются во время выполнения
+с помощью значений из структуры `init::LateResources`, возвращаемой функцией `init`.
-Поздние ресурсы определяются как обычные ресурсы, но им присваивается начальное
-значение `()` (the unit value). `init` должен вернуть начальные значения для
-всех поздних ресурсов, упакованные в структуру типа `init::LateResources`.
+Поздние ресурсы полезны, например, для *move* (передача владения) периферии,
+инициализированной в `init`, в задачи.
-В примере ниже использованы поздние ресурсы, чтобы установить неблокированный,
-односторонний канал между обработчиком прерывания `UART0` и функцией `idle`.
-Очередь типа один производитель-один потребитель [`Queue`] использована как канал.
-Очередь разделена на элементы потребителя и поизводителя в `init` и каждый элемент
-расположен в отдельном ресурсе; `UART0` владеет ресурсом произодителя, а `idle`
-владеет ресурсом потребителя.
+Пример ниже использует поздние ресурсы, чтобы установить неблокируемый односторонний канал
+между обработчиком прерывания `UART0` и задачей `idle`. Для канала использована очередь типа
+один производитель-один потребитель [`Queue`]. Структура очереди разделяется на потребителя
+и производителя в `init`, а затем каждая из частей располагается в отдельном ресурсу;
+`UART0` владеет ресурсом производителя, а `idle` владеет ресурсом потребителя.
[`Queue`]: ../../../api/heapless/spsc/struct.Queue.html
@@ -98,25 +104,46 @@ $ cargo run --example lock
``` console
$ cargo run --example late
-{{#include ../../../../ci/expected/late.run}}```
+{{#include ../../../../ci/expected/late.run}}
+```
+
+## Только разделяемый доступ
+
+По-умолчанию фреймворк предполагает, что все задачи требуют эксклюзивный доступ (`&mut-`) к ресурсам,
+но возможно указать, что задаче достаточен разделяемый доступ (`&-`) к ресурсы с помощью синтакисиса
+`&resource_name` в списке `resources`.
-## `static`-ресурсы
+Преимущество указания разделяемого досупа (`&-`) к ресурсу в том, что для доступа к ресурсу
+не нужна блокировка, даже если за ресурс соревнуются несколько задач, запускаемые с
+разными приоритетами. Недостаток в том, что задача получает только разделяемую ссылку (`&-`)
+на ресурс, и ограничена операциями, возможными с ней, но там, где разделяемой ссылки достаточно,
+такой подход уменьшает количесво требуемых блокировок.
+В дополнение к простым неизменяемым данным, такой разделяемый доступ может быть полезен для
+ресурсов, безопасно реализующих внутреннюю мутабельность с самоблокировкой или атомарными операциями.
-Переменные типа `static` также можно использовать в качестве ресурсов. Задачи
-могут получать только (разделяемые) `&` ссылки на ресурсы, но блокировки не
-нужны для доступа к данным. Вы можете думать о `static`-ресурсах как о простых
-`static`-переменных, которые можно инициализировать в рантайме и иметь лучшие
-правила видимости: Вы можете контролировать, какие задачи получают доступ к
-переменной, чтобы переменная не была видна всем фунциям в область видимости,
-где она была объявлена.
+Заметьте, что в этом релизе RTIC невозможно запросить и эксклюзивный доступ (`&mut-`)
+и разделяемый (`&-`) для *одного и того же* ресурса из различных задач.
+Попытка это сделать приведет к ошибке компиляции.
-В примере ниже ключ загружен (или создан) в рантайме, а затем использован в двух
-задачах, запущенных на разных приоритетах.
+В примере ниже ключ (например криптографический ключ) загружается (или создается) во время выполнения,
+а затем используется двумя задачами, запускаемымы с различным приоритетом без каких-либо блокировок.
``` rust
-{{#include ../../../../examples/static.rs}}
+{{#include ../../../../examples/only-shared-access.rs}}
```
``` console
-$ cargo run --example static
-{{#include ../../../../ci/expected/static.run}}```
+$ cargo run --example only-shared-access
+{{#include ../../../../ci/expected/only-shared-access.run}}
+```
+
+## Неблокируемый доступ к изменяемым ресурсам
+
+Есть две других возможности доступа к ресурсам
+
+* `#[lock_free]`: могут быть несколько задач с одинаковым приоритетом,
+ получающие доступ к ресурсу без критических секций. Так как задачи с
+ одинаковым приоритетом никогда не могут вытеснить друг друга, это безопасно.
+* `#[task_local]`: в этом случае должна быть только одна задача, использующая
+ этот ресурс, так же как локальный `static mut` ресурс задачи, но (опционально) устанавливаемая с в init.
+