Читаем Real-Time Interrupt-driven Concurrency полностью

Для задач, вызываемых из init мы имеем точную информацию о их scheduled времени. Для аппаратных задач такого времени нет, поскольку они асинхронны по природе. Для аппаратных задач среда исполнения предоставляет время запуска (start), которое отражает время, в которое обработчик прерывания будет запущен.

Заметьте, что start не равно времени прихода события, которое вызывает задачу. В зависимости от приоритета задачи и загрузки системы, время start может сильно отдалиться от времени прихода события.

Какое по вашему мнению будет значение scheduled для программных задач, которые вызываются через spawn вместо планирования? Ответ в том, что вызываемые задачи наследуют базовое время того контекста, который их вызывает. Базовое время аппаратных задач - это их время start, базовое время программных задач - их время scheduled, а базовое время init - время старта системы, или нулевое (Instant::zero()). idle на самом деле не имеет базового времени, но задачи вызываемые из нее, используют Instant::now() в качестве базового.

Пример ниже демонстрирует разные смыслы базового времени.

#![allow(unused)]

fn main() {

{{#include ../../../../examples/baseline.rs}}

}

Запуск программы на реальном оборудовании приведет к следующему выводу в консоли:

init(baseline = Instant(0))

foo(baseline = Instant(0))

UART0(baseline = Instant(904))

foo(baseline = Instant(904))

<p id="Типы_send_и_sync"><strong><a l:href="#Типы_send_и_sync">Типы, Send и Sync</a></strong></p>

Каждая функция в модуле app принимает структуру Context в качесте первого параметра. Все поля этих структур имеют предсказуемые, неанонимные типы, поэтому вы можете написать обычные функции, принимающие их как аргументы.

Справочник по API определяет как эти типы генерируются на основе входных данных. Вы можете также сгенерировать документацию к вашему крейту программы (cargo doc --bin ); в документации вы найдете структуры Context (например init::Context и idle::Context).

Пример ниже показывает различные типы, сгенерированные атрибутом app.

#![allow(unused)]

fn main() {

{{#include ../../../../examples/types.rs}}

}

<p id="send"><code><strong><a l:href="#send">Send</a></strong></code></p>

Send - это маркерный трейт для "типов, которые можно передавать через границы потоков", как это определено в core. В контексте RTIC трейт Send необходим только там, где возможна передача значения между задачами, запускаемыми на разных приоритетах. Это возникает в нескольких случаях: при передаче сообщений, в разделяемых static mut ресурсах и при инициализации поздних ресурсов.

Атрибут app проверит, что Send реализован, где необходимо, поэтому вам не стоит волноваться об этом. В настоящий момент все передаваемые типы в RTIC должны быть Send, но это ограничение возможно будет ослаблено в будущем.

<p id="sync"><code><strong><a l:href="#sync">Sync</a></strong></code></p>

Аналогично, Sync - маркерный трейт для "типов, на которые можно безопасно разделять между потоками", как это определено в core. В контексте RTIC типаж Sync необходим только там, где возможно для двух или более задач, запускаемых на разных приоритетах получить разделяемую ссылку (&-) на ресурс. Это возникает только (&-) ресурсах с разделяемым доступом.

Атрибут app проверит, что Sync реализован, где необходимо, но важно знать, где ограничение Sync не требуется: в (&-) ресурсах с разделяемым доступом, за которые соперничают задачи с одинаковым приоритетом.

В примере ниже показано, где можно использовать типы, не реализующие Sync.

#![allow(unused)]

fn main() {

//! `examples/not-sync.rs`

// #![deny(unsafe_code)]

#![deny(warnings)]

#![no_main]

#![no_std]

use core::marker::PhantomData;

use panic_semihosting as _;

pub struct NotSync {

_0: PhantomData<*const ()>,

}

unsafe impl Send for NotSync {}

#[rtic::app(device = lm3s6965, dispatchers = [SSI0])]

mod app {

use super::NotSync;

use core::marker::PhantomData;

use cortex_m_semihosting::debug;

#[shared]

struct Shared {

shared: NotSync,

}

#[local]

struct Local {}

#[init]

fn init(_: init::Context) -> (Shared, Local, init::Monotonics) {

debug::exit(debug::EXIT_SUCCESS);

(

Shared {

shared: NotSync { _0: PhantomData },

},

Local {},

init::Monotonics(),

)

}

#[task(shared = [&shared])]

Перейти на страницу:

Похожие книги

Компьютерные сети. 6-е изд.
Компьютерные сети. 6-е изд.

Перед вами шестое издание самой авторитетной книги по современным сетевым технологиям, написанное признанным экспертом Эндрю Таненбаумом в соавторстве со специалистом компании Google Дэвидом Уэзероллом и профессором Чикагского университета Ником Фимстером. Первая версия этого классического труда появилась на свет в далеком 1980 году, и с тех пор каждое издание книги неизменно становилось бестселлером. В книге последовательно изложены основные концепции, определяющие современное состояние компьютерных сетей и тенденции их развития. Авторы подробно объясняют устройство и принципы работы аппаратного и программного обеспечения, рассматривают все аспекты и уровни организации сетей — от физического до прикладного. Изложение теоретических принципов дополняется яркими, показательными примерами функционирования интернета и компьютерных сетей различного типа. Большое внимание уделяется сетевой безопасности. Шестое издание полностью переработано с учетом изменений, произошедших в сфере сетевых технологий за последние годы, и, в частности, освещает такие технологии, как DOCSIS, 4G и 5G, беспроводные сети стандарта 802.11ax, 100-гигабитные сети Ethernet, интернет вещей, современные транспортные протоколы CUBIC TCP, QUIC и BBR, программно-конфигурируемые сети и многое другое.

Дэвид Уэзеролл , Ник Фимстер , Эндрю Таненбаум

Учебные пособия, самоучители