Jump to content

    
Sign in to follow this  
hound

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

Recommended Posts

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

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

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

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

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

 

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

 

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

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

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

 

 

Share this post


Link to post
Share on other sites

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

 

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

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

 

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

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

 

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

 

Share this post


Link to post
Share on other sites
Bulya, вариант да, но не охота создавать еще другие таски, стараюсь придерживаться принципа: 1-девайс подключенный к МК - 1 таск для него.
Edited by hound

Share this post


Link to post
Share on other sites

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

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

 

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

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

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

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

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

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

 

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

 

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

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

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

 

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

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

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

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

Share this post


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

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

 

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

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

Share this post


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

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

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

 

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

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

 

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

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

 

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

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

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

 

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

 

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

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

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

 

Share this post


Link to post
Share on other sites

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

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

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

 

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

есть 2 таска,

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

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

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

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this