реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> TNKernel переход в другую часть таска
hound
сообщение Apr 25 2015, 14:32
Сообщение #1





Группа: Участник
Сообщений: 12
Регистрация: 15-02-15
Пользователь №: 85 179



Добрый день, есть таск для работы с некоторым внешним устройством.
Устройство общается с МК по юарту, данные в прерывании складываются в буфер и очередьми отправляется в этот таск.
В таксе есть основной бесконечный цикл, в котором по очереди выполняются разные функции.
Т.е, грубо говоря:
Код
while (1) {
  func_1();
  func_2();
  func_3();
  func_4();
  func_5();  
}


Время выполнения каждой функции разное, примерно от 100мс до 1 сек.

Но само устройство может перейти в другой режим работы, для которого нужно будет выполнять уже другие функции. И устройство может перейти в этот режим в любой момент.
Когда устройство переходит в другой режим оно отправляет определенное сообщение МК. Это сообщение отлавливается в прерывании и дальше уже нужно заставить таск выйти из этого цикла и перейти в другой. Каким способ лучше подобное реализовать?
Проверка на наличии сообщения о переходе в другой режим при проверки очереди в каждой функции не вариант, т.к функций в основном цикле может быть намного больше и каждый раз делать проверку кажется лишним.

Go to the top of the page
 
+Quote Post
Bulya
сообщение May 14 2015, 11:46
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 11-10-08
Из: Харьков
Пользователь №: 40 874



Что-то долго без ответа. Уже, наверное, и не актуально.

Исходя из описания, "другой режим" должен быть реализован как другой таск.
Скорее всего с более высоким приоритетом, чем первый.

Этот другой таск должен проинициализироваться и заблокироваться любым примитивом синхранизации (семафор, ивент, чтение очереди - в завсимости от необходимости передачи ему данных из прерывания)
В прерывании по сообщеню смены режима этот таск должен будиться. Если его приоритет выше - он начнет выполнятся сразу по выходу из прерывания.

Остальные детали зависят от того, есть ли у него общие данные с основным режимом и нужно ли будет потом вернутся в основной режим (и с какого момента продолжить выполнение).
Go to the top of the page
 
+Quote Post
hound
сообщение May 15 2015, 06:10
Сообщение #3





Группа: Участник
Сообщений: 12
Регистрация: 15-02-15
Пользователь №: 85 179



Bulya, вариант да, но не охота создавать еще другие таски, стараюсь придерживаться принципа: 1-девайс подключенный к МК - 1 таск для него.

Сообщение отредактировал hound - May 15 2015, 06:10
Go to the top of the page
 
+Quote Post
Bulya
сообщение May 15 2015, 10:51
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 11-10-08
Из: Харьков
Пользователь №: 40 874



Таск имеет один поток выполнения.
Вам требуется либо два потока, либо два состояния.

Если девайс должен переключатся между двумя режимами, то он может это делать переключение синхронно:
- по окончании текущей итерации (проверка флага в начале тела цикла);
- либо в определенных контрольных точках (между функциями или внутри них, но тогда нужно предусмотреть код возврата, проверяемый во внешнем цикле после каждой функции).
При синхронном обнаружении переключения режима:
- выход из цикла и переход к исполнению соответстующего кода (имплементация кооперативной многопоточности);
- либо, если "другой режим" относительно кратковременный и из него нужно возобновить работу в основном цикле, можно просто синхронно вызвать функцию работы этого режима (иммитация програмного прерывания).

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

Но зачем нужны увечные велосипеды, если можно использовать детерминированные подходы:
- два отдельных потока (если режимы независимы и между ними нужно переключаться, возобновляя прерванную работу);
- машина состояний (если переключение режима должно полностью прекратить текущую работу).

Но для машины состояний нужно, чтобы все входные сообщения для таска шли через одну очередь.
Тогда в начале цикла производится ожидание сообщения и затем - выбор функции обработчика в зависимости от режима и его состояния.
Go to the top of the page
 
+Quote Post
VslavX
сообщение May 17 2015, 09:52
Сообщение #5


embarrassed systems engineer
*****

Группа: Свой
Сообщений: 1 083
Регистрация: 24-10-05
Из: Осокорки
Пользователь №: 10 038



У меня была похожая задача - прикладники перенесли очень старый софт под TNKernel и им иногда требовалось откуда-то из глубины приложения "вдруг все бросить" и начать исполнять совершенно другой кусок. Решилось завершением задачи и ее автоматическим рестартом с параметром, а код в начале задачи проверял параметр и переходил на начало нужной ветки.
Go to the top of the page
 
+Quote Post
hound
сообщение May 17 2015, 13:15
Сообщение #6





Группа: Участник
Сообщений: 12
Регистрация: 15-02-15
Пользователь №: 85 179



Переход в другую задачу еще не совсем вариант, потому что это в этом "другом режиме работы" нужно девайсу отправить буквально одну команду.
Идеальным вариантом было бы при получении в прерывании уведомления о этом режиме, например, выставлять флаг и запускать сразу следующую итерацию цикла.
Перезапуск основной задачи тоже не вариант, т.к в начале этой задачи идет инициализация этого устройства и его первая перезагрузка, что в "разгаре" работы нельзя делать.
Go to the top of the page
 
+Quote Post
VslavX
сообщение May 17 2015, 20:32
Сообщение #7


embarrassed systems engineer
*****

Группа: Свой
Сообщений: 1 083
Регистрация: 24-10-05
Из: Осокорки
Пользователь №: 10 038



Цитата(hound @ May 17 2015, 16:15) *
Перезапуск основной задачи тоже не вариант, т.к в начале этой задачи идет инициализация этого устройства и его первая перезагрузка, что в "разгаре" работы нельзя делать.

И в чем проблема? При старте/рестарте задачи посмотрели на параметр, переданный задаче и делаем инициализацию/перезагрузку устройства только при первом старте или если по логике нужно, в остальных ненужных случаях - инициализацию пропускаем и сразу переходим "куда надо".

Вот так делается однократная инициализация:
Код
//________________________________________________________________
//
void sample_task_start(void *param)
{
    if (param == (void*)SUC_HReset)
    {
        //
        // Выполняем инициализацию
        //
        do_some_init();
    }
    //
    // Вызываем пользовательскую задачу в цикле
    //
     do_user_code(param);
}
Go to the top of the page
 
+Quote Post
Bulya
сообщение May 18 2015, 12:54
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 11-10-08
Из: Харьков
Пользователь №: 40 874



Цитата(hound @ May 17 2015, 16:15) *
Переход в другую задачу еще не совсем вариант, потому что это в этом "другом режиме работы" нужно девайсу отправить буквально одну команду.

Если нужно отправить одну команду и вернуться в основной режим, то нужно просто синхронно выполнить одну функцию с отправкой этой команды.
Но за "буквально" могут скрываться неприятные нюансы.

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

Для того, чтобы при получении определенного сообщения завершить текущую итерацию, стек функций от корня итерации до чтения этого сообщения должен поддерживать код возврата, который обрабатывается как и любая нештатная ситуация и приводит к досрочному завершению текущей операции.

Сложно что-то советовать когда непонятны критерии выбора решения.
К чему такая экономия на задачах? Не хватает памяти? (При том, что судя по всему требуемый объем стека небольшой и легко прогнозируем.)

Если итерацию основного режима все-равно нужно прервать, то в ней так или иначе необходима обработка исключений.
А значит переключение режима должно эскалироваться как любая ошибка и приводить к началу новой итерации.
И там в самом начале итерации должен проверяться какой-то флаг и обрабатываться "другой режим".

А вообще нужно просто организовать задачу в виде стейт-машины. И все переключения режимов сразу станут штатными ситуациями.

Проблемма, судя по всему в том, что задача принимает сообщения в разных местах кода или даже принимает сообщения из нескольких очередей.
Это в принципе плохо - повышает количество гонок и вероятность взаминых блокировок.
Нужно стремиться к тому, чтобы поток, обрабатывающий события, получал их в одном месте и из одного источника.
Go to the top of the page
 
+Quote Post
hound
сообщение May 27 2015, 18:14
Сообщение #9





Группа: Участник
Сообщений: 12
Регистрация: 15-02-15
Пользователь №: 85 179



В общем, думаю сделать следующее:
при получении в прерывании сигнала о "другом режиме" выставлять флаг и в начале цикла этот флаг проверять, если он выставлен - выполнить нужное действие и дальше вернуться в "стандартный" режим.
Обмен идет только синхронный, отправили команду устройству - ждем от него ответа, ответ получен отправляем следующую команду и так до бесконечности.

А, например, как лучше поступить с такой задачей:
есть 2 таска,
первый таск отправляет через очередь сообщение второму таску,
во втором таске это сообщение обрабатывается и ответ отправляется обратно первому таску.
Городить 2 очереди?
В первой исходящее сообщение, а во второй ждем ответа?
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 16th June 2025 - 16:08
Рейтинг@Mail.ru


Страница сгенерированна за 0.01392 секунд с 7
ELECTRONIX ©2004-2016