Перейти к содержанию
    

TNKernel переход в другую часть таска

Добрый день, есть таск для работы с некоторым внешним устройством.

Устройство общается с МК по юарту, данные в прерывании складываются в буфер и очередьми отправляется в этот таск.

В таксе есть основной бесконечный цикл, в котором по очереди выполняются разные функции.

Т.е, грубо говоря:

while (1) {
  func_1();
  func_2();
  func_3();
  func_4();
  func_5();  
}

 

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

 

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

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

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

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Скорее всего с более высоким приоритетом, чем первый.

 

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

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

 

Остальные детали зависят от того, есть ли у него общие данные с основным режимом и нужно ли будет потом вернутся в основной режим (и с какого момента продолжить выполнение).

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Таск имеет один поток выполнения.

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

 

Если девайс должен переключатся между двумя режимами, то он может это делать переключение синхронно:

- по окончании текущей итерации (проверка флага в начале тела цикла);

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

При синхронном обнаружении переключения режима:

- выход из цикла и переход к исполнению соответстующего кода (имплементация кооперативной многопоточности);

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

 

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

 

Но зачем нужны увечные велосипеды, если можно использовать детерминированные подходы:

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

- машина состояний (если переключение режима должно полностью прекратить текущую работу).

 

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

Тогда в начале цикла производится ожидание сообщения и затем - выбор функции обработчика в зависимости от режима и его состояния.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня была похожая задача - прикладники перенесли очень старый софт под TNKernel и им иногда требовалось откуда-то из глубины приложения "вдруг все бросить" и начать исполнять совершенно другой кусок. Решилось завершением задачи и ее автоматическим рестартом с параметром, а код в начале задачи проверял параметр и переходил на начало нужной ветки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Перезапуск основной задачи тоже не вариант, т.к в начале этой задачи идет инициализация этого устройства и его первая перезагрузка, что в "разгаре" работы нельзя делать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Перезапуск основной задачи тоже не вариант, т.к в начале этой задачи идет инициализация этого устройства и его первая перезагрузка, что в "разгаре" работы нельзя делать.

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

 

Вот так делается однократная инициализация:

//________________________________________________________________
//
void sample_task_start(void *param)
{
    if (param == (void*)SUC_HReset)
    {
        //
        // Выполняем инициализацию
        //
        do_some_init();
    }
    //
    // Вызываем пользовательскую задачу в цикле
    //
     do_user_code(param);
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Но за "буквально" могут скрываться неприятные нюансы.

 

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

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

 

Сложно что-то советовать когда непонятны критерии выбора решения.

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

 

Если итерацию основного режима все-равно нужно прервать, то в ней так или иначе необходима обработка исключений.

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

И там в самом начале итерации должен проверяться какой-то флаг и обрабатываться "другой режим".

 

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

 

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

Это в принципе плохо - повышает количество гонок и вероятность взаминых блокировок.

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В общем, думаю сделать следующее:

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

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

 

А, например, как лучше поступить с такой задачей:

есть 2 таска,

первый таск отправляет через очередь сообщение второму таску,

во втором таске это сообщение обрабатывается и ответ отправляется обратно первому таску.

Городить 2 очереди?

В первой исходящее сообщение, а во второй ждем ответа?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...