# Ресурсы Фреймворк предоставляет абстракцию для разделения данных между любыми контекстами, с которыми мы встречались в предыдущей главе (задачами-обработчиками, `init` и `idle`): ресурсы. Ресурсы - это данные, видимые только функциями, определенными внутри модуля `#[app]`. Фреймворк дает пользователю полный контроль за тем, какой контекст может получить доступ к какому ресурсу. Все ресурсы определены в одной структуре внутри модуля `#[app]`. Каждое поле структуры соответствует отдельному ресурсу. `struct`-ура должна быть аннотирована следующим атрибутом: `#[resources]`. Ресурсам могут быть опционально даны начальные значения с помощью атрибута `#[init]`. Ресурсы, которым не передано начально значение, называются *поздними* ресурсами, более детально они описаны в одном из разделов на этой странице. Каждый контекс (задача-обработчик, `init` или `idle`) должен указать ресурсы, к которым он намерен обращаться, в соответсятвующем ему атрибуте с метаданными, используя аргумент `resources`. Этот аргумент принимает список имен ресурсов в качестве значения. Перечисленные ресурсы становятся доступны в контексте через поле `resources` структуры `Context`. Пример программы, показанной ниже содержит два обработчика прерывания, которые разделяют доступ к ресурсу под названием `shared`. ``` rust {{#include ../../../../examples/resource.rs}} ``` ``` console $ cargo run --example resource {{#include ../../../../ci/expected/resource.run}} ``` Заметьте, что к ресурсу `shared` нельзя получить доступ из `idle`. Попытка сделать это приведет к ошибке компиляции. ## `lock` Критические секции необходимы для разделения изменяемых данных таким образом, чтобы избежать гонок данных. Поле `resources`, передаваемого `Context` реализует трейт [`Mutex`] для каждого разделяемого ресурса, доступного задаче. Единственный метод этого трейта, [`lock`], запускает свой аргумент-замыкание в критической секции. [`Mutex`]: ../../../api/rtic/trait.Mutex.html [`lock`]: ../../../api/rtic/trait.Mutex.html#method.lock Критическая секция, создаваемая интерфейсом `lock` основана на динамических приоритетах: она временно повышает динамический приоритет контекста до *максимального* приоритета, что не дает другим задачам возможности вытеснить критическую секцию. Этот протокол синхронизации известен как [Протокол немедленного максимального приоритета (ICPP)][icpp], и компилируется диспетчером RTIC с [Политикой ресурсов стека(SRP)][srp]. [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}} ``` ``` console $ cargo run --example lock {{#include ../../../../ci/expected/lock.run}} ``` ## Множественное блокировка Это расширение к `lock`, чтобы уменьшить количесво отступов, блокируемые ресурсы можно объединять в кортежи. Следующий пример это демонстрирует: ``` rust {{#include ../../../../examples/multilock.rs}} ``` ## Поздние ресурсы Поздние ресурсы - такие ресурсы, которым не передано начальное значение во время компиляции с помощью атрибута `#[init]`, но которые вместо этого инициализируются во время выполнения с помощью значений из структуры `init::LateResources`, возвращаемой функцией `init`. Поздние ресурсы полезны, например, для *move* (передача владения) периферии, инициализированной в `init`, в задачи. Пример ниже использует поздние ресурсы, чтобы установить неблокируемый односторонний канал между обработчиком прерывания `UART0` и задачей `idle`. Для канала использована очередь типа один производитель-один потребитель [`Queue`]. Структура очереди разделяется на потребителя и производителя в `init`, а затем каждая из частей располагается в отдельном ресурсу; `UART0` владеет ресурсом производителя, а `idle` владеет ресурсом потребителя. [`Queue`]: ../../../api/heapless/spsc/struct.Queue.html ``` rust {{#include ../../../../examples/late.rs}} ``` ``` console $ cargo run --example late {{#include ../../../../ci/expected/late.run}} ``` ## Только разделяемый доступ По-умолчанию фреймворк предполагает, что все задачи требуют эксклюзивный доступ (`&mut-`) к ресурсам, но возможно указать, что задаче достаточен разделяемый доступ (`&-`) к ресурсы с помощью синтакисиса `&resource_name` в списке `resources`. Преимущество указания разделяемого досупа (`&-`) к ресурсу в том, что для доступа к ресурсу не нужна блокировка, даже если за ресурс соревнуются несколько задач, запускаемые с разными приоритетами. Недостаток в том, что задача получает только разделяемую ссылку (`&-`) на ресурс, и ограничена операциями, возможными с ней, но там, где разделяемой ссылки достаточно, такой подход уменьшает количесво требуемых блокировок. В дополнение к простым неизменяемым данным, такой разделяемый доступ может быть полезен для ресурсов, безопасно реализующих внутреннюю мутабельность с самоблокировкой или атомарными операциями. Заметьте, что в этом релизе RTIC невозможно запросить и эксклюзивный доступ (`&mut-`) и разделяемый (`&-`) для *одного и того же* ресурса из различных задач. Попытка это сделать приведет к ошибке компиляции. В примере ниже ключ (например криптографический ключ) загружается (или создается) во время выполнения, а затем используется двумя задачами, запускаемымы с различным приоритетом без каких-либо блокировок. ``` rust {{#include ../../../../examples/only-shared-access.rs}} ``` ``` console $ cargo run --example only-shared-access {{#include ../../../../ci/expected/only-shared-access.run}} ``` ## Неблокируемый доступ к изменяемым ресурсам Есть две других возможности доступа к ресурсам * `#[lock_free]`: могут быть несколько задач с одинаковым приоритетом, получающие доступ к ресурсу без критических секций. Так как задачи с одинаковым приоритетом никогда не могут вытеснить друг друга, это безопасно. * `#[task_local]`: в этом случае должна быть только одна задача, использующая этот ресурс, так же как локальный `static mut` ресурс задачи, но (опционально) устанавливаемая с в init.