Пример хороший, сохранил. Я пока только «въезжаю» сложноват для меня. Мне бы сейчас понять, как строить приложение. Например, есть задача, как ее правильно ее реализовать?
На TFT индикаторе, по нажатию рисуется круг, через энное время его стираем. Можно сделать через очередь, завести две задачи, первая, по событию, рисует и заряжает очередь на стереть для другой задачи. Во второй задаче опять работа с общим ресурсом SPI. Или завести 3 задачи, в третей вся работа с SPI.
Как быть если задача рисования - это целый интерфейс, меню, часы и т.д., реализовывать конечный автомат в задаче с разбором очереди? Как это делается? Нет пока понятия, это решение, как мне сейчас видится, неоптимально по коду.
И кстати, посмотрел что SPI в esp32 реализован через семафоры, в первом моем сообщении проблема решается объявлением TFT_eSPI tft = TFT_eSPI(); в теле каждой задачи использующей spi. То есть работу с индикатором можно растащить по задачам.
Организовать и использовать флаг занятости SPI
Пока в описанной задаче нет потребности в нескольких потоках. Пока - простой автомат.
Это называется “семафор”. Чаще используют слово mutex.
Какой модуль display+touch используется ???
Я в курсе ![]()
Выше написал, что так делать не надо никогда. Ты хочешь принципы программирования изучить или свои придумать? Если второе, то “флаг” в руки! ![]()
Что-то в интернетах пишут, что семафор и мьютекс - слегка разные вещи, но я так и не уловил этой тонкой разницы.
Семафор - много значений, мьютекс - два значения - занят-не занят. Иначе бинарный семафор. Плюс отдать может лишь тот, кто взял. Короче мьютекс это то, что реально нужно от семафора, если мы не ведем речь о сложной многопроцессорной системе.
Знаешь, это примерно как посудомойка с 15-ю режимами, когда нужна одна кнопка - “включить”. И про все режимы ты не помнишь уже через неделю после покупки. ![]()
В принципе, при типичных задачах, всё без исключения общение потоков можно реализовать на очередях и мьютексах. И даже только на очередях.
разные: mutex используется для доступа к общему ресурсу , например к области памяти или драйверу .
семафор же, удобно использовать для синхронизации процессов :например у вас есть задача передать комнаду с компа через UART в устройство, т.е. ,например пока , минимум n байт с компа приняты не будет , запускать обрабочик команд нет смысла, вот тогда и может пригодиться семаофор : драйвер UART даст сигнал семафору обработчика команд когда примит минимум n байт.
Семафор вешается на ресурс, а мьютекс на задачу.
сразу видно, кто здесь с 100 ваттным паяльником дело имел )))
Со 100 ваттным советским паяльником. Нынешние сотки уже совсем не те, что раньше - маленькие, аккуратненькие, с тоненькими жалами ![]()
Сорян за некропост.
Вот как раз сейчас столкнулся с задачей: на ESP32: регулярное получение метрик и выпихивание их наружу с большим периодом + сон.
Не знаю, как полагается по-научному делать, реализовал так: при появлении новых значений метрик от перефирии, в майнлупе поднимается булевый флаг “не спать”, метрика суется в очередь, которую слушает отдельная задача “посылателя”. Посылатель скоко-то там непредсказуемо копошится (МК майнлупом не усыпляется), в финале семафорит - “закончил”. Майнлуп видит семафор, сбрасывает флаг “не спать” и начинает укладывать МК в сон между опросами перефирии.
Все правильно или есть покрасивше вариант?
Читал ещё, что нотифаи работают быстрее семафоров, но пока не понял - есть ли существенная выгода.
Старый анекдот.
Сидит программист глубоко в отладке. Подходит сынишка:
- Папа, почему солнышко каждый день встаёт на востоке, а садиться на западе?
- Ты это проверял?
- Проверял.
- Хорошо проверял?
- Хорошо.
- Работает?
- Работает.
- Каждый день работает?
- Да, каждый день.
- Тогда ради бога, сынок, ничего не трогай и не меняй.
(с)
Я это к тому, что все сделано правильно и умно. Перфекционизм - тяжелый психический недуг!
Не заболей им!
вот это объяснение не понял . мьютекс же тоже «оборачивает» общий ресурс - область памяти,периферию предотвращая «одновременный» доступ к ресурсу.ты имеешь ввиду как только процесс хватает мьютекс,то прсоцесс им владеет,то есть мъютекс висит на процессе и только конкретный процесс может освободить «захваченный» им мъютекс?
а метрики это 1 пакет данных или несколько?
если привести твой пример к моему способу , если я правильно понял .то тот семафор который ждет майнлуп и должен работать как тот флаг который «не спать» и иначе, как я понял у тебя «маинлооп» в какой то момент торчит на семафоре ожидая когда «посылатель» даст «добро».
но кмк ,вообще правильно делать так :
определить 3 таска : mainloop, «посылатель» , “low power task”.у первых двух приоритет выше чем у «low power” . как только mainloop и «посылатель» закончили свои дела ,они добровольно оставляют процессор , и только тогда “low power task” занимает процессор и если нет никаких ожидаемых событий по таймерам в ближайшие N миллисекунд , вводит процессор в low power
Основная метрика одна - появляется после цикла опросов переферийного устройства по UART. Ну, и вспомогательные - статистика работы системы и т.п.
Не совсем. Майнлуп - типа диспетчера. Кнопки опрашивает, запускает задачу съёма метрик, всякие там светодиоды поджигает на некоторое время. Тяжелое наследие однозадачности, вобщем. И этот диспетчер на семафоре не висит, а чекает его быстро. Ну так, рабоче-крестьянская многозадачность. Типа такого:
void loop() {
static bool dontSleep;
// Проверяем кнопки
...
// Мигаем неонкой
...
// Получаем метрики
if (pdTRUE == xQueueReceive(queueRecv, &queueItemRecv, pdMS_TO_TICKS(0x00))) {
...
strlcpy(queueItemSend.dataReport, queueItemRecv.dataReport,
sizeof(queueItemSend.dataReport));
...
}
...
// Шлём отчеты
if (нужно слать отчёт) {
dontSleep = true;
xQueueSend(queueSend, &queueItemSend, 0x00);
}
// Чекаем семафор
if (pdTRUE == xSemaphoreTake(shReportingDone, pdMS_TO_TICKS(0x00))) { }
dontSleep = false;
}
// Спим
if (!dontSleep ) { doze(); }
}
void taskReporting(void* _pvParameters) {
...
while (true) {
if (pdFALSE == xQueueReceive(queueSend, &queueItemSend, portMAX_DELAY)) { continue; }
...
// творим разные сетевые дела
wifiActivate(...);
...
wifiDeactivate(...);
// семафорим диспетчеру
xSemaphoreGive(shReportingDone);
}
}
[quote=“mixail844, post:38, topic:10693”]
определить 3 таска : mainloop, «посылатель» , “low power task”.у первых двух приоритет выше чем у «low power” . как только mainloop и «посылатель» закончили свои дела ,они добровольно оставляют процессор [/quote]
Т.е. параллельные задачи забирают свои семафоры при начале активити, “low power task” тоже пытается захватить семафоры и, если вышло хапнуть все, сразу засыпает. Так?
Тогда меня смущает следующее: диспетчер суёт в очередь метрики, “посылатель” обнаруживает данные в очереди, захватывает семафор делает свои дела, отдаёт семафор - вроде всё красиво, но есть промежуток времени между посыланием метрик диспетчером и захватом семафора посылателем, в который диспетчер потенциально успеет уложить систему в сон и репорт будет отослан с опозданием. Этого желательно избежать. Как купировать такое развитие событий?
Поднимает флаг запрета сна тот, кто “ложЫт” в очередь, опускает флаг тот, кто вынает из ёй.
А без выпенджёжа - просто проверять очередь на наличие в ней чего-то - xQueuePeek()
не совсем, у low power task нет семафора который он хватает/отпускает ,low power task постоянно находится в состоянии ready пока остальные таски делают свои дела. потому что у low power task самый низкий приоритет и ОС никогда ему не даст время быть active и не даст устройству пойти спать.
т.е единственная задача low power task это вводить и выводить устройство в сон , но не факт что устройство будет спать при активном LPT . потому что у тебя могут быть пассивные процессы(ожидание ответа откуда то,например ) и время сна либо не выгодно энергетически, либо пробуждение дольше по времени чем ожидание ответа.