diff options
| author | Andrey Zgarbul <zgarbul.andrey@gmail.com> | 2021-04-04 08:15:13 +0300 |
|---|---|---|
| committer | Andrey Zgarbul <zgarbul.andrey@gmail.com> | 2021-04-08 12:22:43 +0300 |
| commit | 05bda2b1bd2e15f5a20cda1444992eb9b6c8887e (patch) | |
| tree | 25330724d4e6d9ea3a62b592c07bfc5799c7da57 /book/ru/src/by-example/resources.md | |
| parent | 83cdf00eecb0f14857b5e0f28e884b2120eabb18 (diff) | |
update russian translation of the book
Diffstat (limited to 'book/ru/src/by-example/resources.md')
| -rw-r--r-- | book/ru/src/by-example/resources.md | 177 |
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. + |
