# Ресурсы Фреймворк предоставляет абстракцию для разделения данных между любыми контекстами, с которыми мы встречались в предыдущей главе (задачами-обработчиками, `init` и `idle`): ресурсы. Ресурсы - это данные, видимые только функциями, определенными внутри модуля `#[app]`. Фреймворк дает пользователю полный контроль за тем, какой контекст может получить доступ к какому ресурсу. Все ресурсы определены в *двух* структурах внутри модуля `#[app]`. Каждое поле этих структур соответствует отдельному ресурсу. Одна `struct`-ура должна быть аннотирована атрибутом `#[local]`. Другая `struct`-ура должна быть аннотирована атрибутом `#[shared]`. Разница между этими двумя множествами ресурсов будет описана познее. Каждый контекс (задача-обработчик, `init` или `idle`) должен указать ресурсы, к которым он намерен обращаться, в соответсятвующем ему атрибуте с метаданными, используя либо аргумент `local`, либо `shared`. Этот аргумент принимает список имен ресурсов в качестве значения. Перечисленные ресурсы становятся доступны в контексте через поля `local` и `shared` структуры `Context`. Во время выполнения при выходе из функции `#[init]` все ресурсы инициализированы. Функция `#[init]` должна возвращать начальные значения для всех ресурсов; отсюда следует, что тип возвращаемого ею значения включает типы структур `#[shared]` и `#[local]`. Поскольку ресурсы инициализированы в ходе функции `#[init]`, к ним нельзя получить доступ внетри функции `#[init]`. Пример программы, показанной ниже содержит два обработчика прерывания. Каждый обработчик имеет доступ к его собственному `#[local]` ресурсу. ``` rust {{#include ../../../../examples/resource.rs}} ``` ``` console $ cargo run --example resource {{#include ../../../../ci/expected/resource.run}} ``` К ресурсу `#[local]` нельзя получить доступ извне задачи к которой он привязан атрибутом `#[task]`. Попытка обращения к одному и тому же ресурсу `#[local]` из более чем одной задачи - ошибка компиляции. ## `lock` Критические секции необходимы для доступа к ресурсам `#[shared]` таким образом, чтобы избежать гонок данных. Поле `shared`, передаваемого `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}} ``` ## Только разделяемый (`&-`) доступ По-умолчанию фреймворк предполагает, что все задачи требуют эксклюзивный доступ (`&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}} ``` ## Неблокируемый доступ к изменяемым ресурсам Критическая секция *не* требуется для доступа к ресурсу `#[shared]`, к которому обращаются только из задач с *одинаковым* приоритетом. В этом случае вы можете избежать `lock` API, добавив атрибут поля `#[lock_free]` при объявдении ресурса (смотреть пример ниже). Заметьте, что это лишь для удобства: даже если вы используете `lock` API, во время выполнения фреймворк *не* создаст критическую секцию. Еще одно ценное замечание: использование `#[lock_free]` на ресурсах, разделяемых задачами, запускаемыми с разными приоритетами приведет к ошибке *компиляции* -- не импользование `lock` API может привести к гонке данных в этом случае. ``` rust {{#include ../../../../examples/lock-free.rs}} ``` ``` console $ cargo run --example lock-free {{#include ../../../../ci/expected/lock-free.run}} ```