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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Обмен данными между задачами RTOS
Rev0.0
сообщение Jan 30 2015, 09:49
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 23
Регистрация: 3-05-13
Пользователь №: 76 718



Привет! Вот мучаюсь и все тут, нужен свежий взгляд. Ниже привел псевдокод, который по моему мнению должен нормально работать.
Имеем некоторую RTOS и 2 задачи для простоты.
Задача task1 имеет приоритет выше, чем task2. Задача task1 висит в ожидании данных от некоторой периферии.
Задача task2 должна принимать ПОСЛЕДНИЕ данные от task1, т.е если задача task1 получила скажем 10 буферов данных, то нам нужен в task2 только последний буфер, остальные можем безболезненно потерять (т.е. очередь не нужна).
Важное условие - код task2 должен выполняться как можно быстрее, поэтому я мьютекс поместил внутрь опроса флага, т.е. чтобы данные блокировались только когда они пришли, а не каждый цикл выполнения task2.
Прав ли я с таким кодом, покритикуйте, пожалуйста.

Код
int a,b,c;
int buf[3];

task1
{
while(1)
{
  if (wait_peri_data(&buf))
  {
    mutex_lock();
    a = buf[0];
    b = buf[1];
    c = buf[2];
    mutex_unlock();
    peri_data_available = 1;
  }
  os_delay(1);
}
}

task2
{
int a_task, b_task, c_task;    

while(1)
{
  if (peri_data_available)
  {
    mutex_lock();        
    a_task = a;
    b_task = b;
    c_task = c;
    mutex_unlock();
    peri_data_available = 0;            
  }
  os_delay(1);
}
}


Сообщение отредактировал Rev0.0 - Jan 30 2015, 09:51
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 30 2015, 10:13
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Rev0.0 @ Jan 30 2015, 11:49) *
покритикуйте, пожалуйста.
А почему вторая задача должна просыпаться каждый тик и проверять переменную? Неужели в вашей ОС нет средства сигнализации вроде флага? Чтобы вторая задача ушла в ожидание этого флага и проснулась только тогда, когда первая задача этот флаг просигналит?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Jan 30 2015, 10:58
Сообщение #3


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Вот так надо делать:

Код
int a,b,c;
int buf[3];

task1
{

while(1)
{
   mutex_lock();
  if (wait_peri_data(&buf))
  {
    a = buf[0];
    b = buf[1];
    c = buf[2];
  }
  mutex_unlock();
  os_delay(1);
}
}

task2
{
int a_task, b_task, c_task;    

while(1)
{
  mutex_lock();        
  a_task = a;
  b_task = b;
  c_task = c;
  mutex_unlock();
  os_delay(1);
}
}
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 30 2015, 11:20
Сообщение #4


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(AlexandrY @ Jan 30 2015, 12:58) *
Вот так надо делать:
И что мы получили? Высокоприоритетная задача вынуждена ждать, пока низкоприоритетная задача отпустит mutex, хотя этот mutex ей для возобновления работы не нужен совсем. Тогда уж запихнуть все тело второй задачи в первую, эффект будет таким же, плюс экономия на стеке второй задачи и времени на переключение между ними.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Jan 30 2015, 11:34
Сообщение #5


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(Сергей Борщ @ Jan 30 2015, 13:20) *
И что мы получили? Высокоприоритетная задача вынуждена ждать, пока низкоприоритетная задача отпустит mutex, хотя этот mutex ей для возобновления работы не нужен совсем. Тогда уж запихнуть все тело второй задачи в первую, эффект будет таким же, плюс экономия на стеке второй задачи и времени на переключение между ними.


Тут как ни крути абсурд будет по причине os_delay в обоих задачах.
А я просто привел к виду принятому в RTOS.
Go to the top of the page
 
+Quote Post
Rev0.0
сообщение Feb 2 2015, 05:58
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 23
Регистрация: 3-05-13
Пользователь №: 76 718



Сергей Борщ
Ах да, забыл сказать, что task2 нельзя делать ожидающей, задумано так, что она должна работать каждый тик, поэтому лишние переключения нежелательны.
Также нежелательно юзать мьютексы каждый раз при входе в задачу, т.к. они довольно ресурсоемки да и задачи выполняют еще какой-то код помимо кода обмена данными. По этим причинам у меня и возникла идея проверять флаг каждый тик и затем если флаг TRUE, то тогда уже используем лок мьютексом.
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Feb 2 2015, 06:08
Сообщение #7


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(Rev0.0 @ Feb 2 2015, 07:58) *
Также нежелательно юзать мьютексы каждый раз при входе в задачу, т.к. они довольно ресурсоемки да и задачи выполняют еще какой-то код помимо кода обмена данными.


Самый ресурсоемкий в ваших примерах это вызов os_delay. На все остальное после этого можно не обращать внимания.
Go to the top of the page
 
+Quote Post
Rev0.0
сообщение Feb 2 2015, 06:51
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 23
Регистрация: 3-05-13
Пользователь №: 76 718



Цитата(AlexandrY @ Feb 2 2015, 11:08) *
Самый ресурсоемкий в ваших примерах это вызов os_delay. На все остальное после этого можно не обращать внимания.

В смысле? Если мне нужно чтобы каждая задача выполнялась периодически, одна с периодом 1 мс, другая 10 мс, третья 100 мс, все задачи с разным приоритетом. Как вы это сделаете? os_delay как раз и нужна для того, чтобы когда высокоприоритетная задача отработала другие имели возможность тоже сделать это. Иначе вся ОС без os_delay будет работать в бесконечном цикле только в одной задаче с самым высоким приоритетом.

Сообщение отредактировал Rev0.0 - Feb 2 2015, 06:52
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 2 2015, 07:11
Сообщение #9


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Rev0.0 @ Feb 2 2015, 07:58) *
Ах да, забыл сказать, что task2 нельзя делать ожидающей, задумано так, что она должна работать каждый тик, поэтому лишние переключения нежелательны.
Недопонял. Ну и что, что каждый тик? Все равно выполняя свой os_delay() вы вызываете переключение. Вот только момент возврата из os_delay() и начала полезной работы у вас получился никак не связан с моментом готовности данных.

Цитата(Rev0.0 @ Feb 2 2015, 07:58) *
Также нежелательно юзать мьютексы каждый раз при входе в задачу, т.к. они довольно ресурсоемки да и задачи выполняют еще какой-то код помимо кода обмена данными.
Опять не вижу связи. Если вы используете мутех при входе в задачу - задача будет ждать, даже если этот мутех ей сейчас нафиг не нужен. Я не знаю, что у вас за ОС, но мне кажется, что тут нужен не мутех, тут нужно оформить a, b, c в виде сообщения и это сообщение послать задаче 2. Возможно через очередь сообщений, а возможно достаточно и вырожденной очереди из одного сообщения. И задача 2 должна ждать появления этого сообщения. Возможно ожидать с таймаутом в один тик. А возможно надо разделить на две задачи ту работу, которую задача2 выполняет по приходу данных и ту работу, которую она должна выполнять периодически.

Цитата(Rev0.0 @ Feb 2 2015, 08:51) *
В смысле? Если мне нужно чтобы каждая задача выполнялась периодически, одна с периодом 1 мс, другая 10 мс, третья 100 мс, все задачи с разным приоритетом. Как вы это сделаете?
В вашей реализации одна задача будет выполняться с периодом 1 мс + некоторое время на ее выполнение + некоторое время на выполнение других задач, вторая - с периодом 10 мс + некоторое время, третья - 100 мс + некоторое заранее неизвестное время.

Цитата(Rev0.0 @ Feb 2 2015, 08:51) *
Иначе вся ОС без os_delay будет работать в бесконечном цикле только в одной задаче с самым высоким приоритетом.
Значит у вас что-то не так с архитектурой программы. Потому что правильно спроектированная программа с ОС все свободное время крутится в цикле задачи с наименьшим приоритетом (IdleTask), а все остальные задачи в свободное время ждут появления запускающего их события.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Rev0.0
сообщение Feb 2 2015, 10:16
Сообщение #10


Участник
*

Группа: Участник
Сообщений: 23
Регистрация: 3-05-13
Пользователь №: 76 718



Может быть я задачу как-то непонятно описал.
Я же просто привел вариант когда нужно в задаче выполнять периодически действия - как вы это сделаете без os_delay? Аппаратный таймер, который шлет задаче семафор? Да, можно, но вопрос не в этом.
Как вы строите архитектуру с RTOS - все задачи чего-то ждут? У меня в проекте 10 задач и некоторые ждут, а некоторые периодически выполняются. Тем задачам, что выполняются периодически нужна связь с ожидающими. Про очередь - хорошая идея, но как я писал выше мне нужны только последние данные - нет смысла в очереди. Тем более мне нужна очередь с нулевым временем ожидания.

Кстати для решения того, что вы описали с нечетким периодом выполнения задач в FreeRTOS, например, есть vTaskDelayUntil.
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Feb 2 2015, 11:10
Сообщение #11


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(Rev0.0 @ Feb 2 2015, 12:16) *
Я же просто привел вариант когда нужно в задаче выполнять периодически действия - как вы это сделаете без os_delay?


Используются сервисы ожидания с таймаутом.
xEventGroupWaitBits с указанием xTicksToWait

Но лучше создать отдельную задачу для строго периодических действий.

Кстати, во Free RTOS хорошо написано почему vTaskDelay нельзя использовать для периодических задач.
Go to the top of the page
 
+Quote Post
Timmy
сообщение Feb 2 2015, 20:57
Сообщение #12


Знающий
****

Группа: Участник
Сообщений: 835
Регистрация: 9-08-08
Из: Санкт-Петербург
Пользователь №: 39 515



Цитата(Rev0.0 @ Jan 30 2015, 12:49) *
Привет! Вот мучаюсь и все тут, нужен свежий взгляд. Ниже привел псевдокод, который по моему мнению должен нормально работать.
Имеем некоторую RTOS и 2 задачи для простоты.
Задача task1 имеет приоритет выше, чем task2. Задача task1 висит в ожидании данных от некоторой периферии.
Задача task2 должна принимать ПОСЛЕДНИЕ данные от task1, т.е если задача task1 получила скажем 10 буферов данных, то нам нужен в task2 только последний буфер, остальные можем безболезненно потерять (т.е. очередь не нужна).
Важное условие - код task2 должен выполняться как можно быстрее, поэтому я мьютекс поместил внутрь опроса флага, т.е. чтобы данные блокировались только когда они пришли, а не каждый цикл выполнения task2.
Прав ли я с таким кодом, покритикуйте, пожалуйста.

Циклический опрос следует применять только в исключительных ситуациях. В вашем случае task2 может непрерывно спать до пробуждения со стороны task1 в момент поступления новых данных. Для пробуждения можно в завимости от OS и ситуации использовать mailbox, semaphore, event и т.п.
И, похоже, вы хотите выкидывать часть входных данных, если они поступают слишком быстро(более одного сэмпла в миллисекунду), но не объявили эту цель в явном виде, и не описали условие выкидывания.
Go to the top of the page
 
+Quote Post
501-q
сообщение Feb 3 2015, 04:20
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 38
Регистрация: 24-02-09
Из: Екатеринбург
Пользователь №: 45 296



Приветствую.

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

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

Цитата(Rev0.0 @ Jan 30 2015, 15:49) *
Привет! Вот мучаюсь и все тут, нужен свежий взгляд. Ниже привел псевдокод, который по моему мнению должен нормально работать.
Имеем некоторую RTOS и 2 задачи для простоты.
Задача task1 имеет приоритет выше, чем task2. Задача task1 висит в ожидании данных от некоторой периферии.
Задача task2 должна принимать ПОСЛЕДНИЕ данные от task1, т.е если задача task1 получила скажем 10 буферов данных, то нам нужен в task2 только последний буфер, остальные можем безболезненно потерять (т.е. очередь не нужна).

Код
volatile int a,b,c;
int buf[3];
volatile int peri_data_available;

task1
{
while(1)
{
  if (wait_peri_data(&buf))
  {
    a = buf[0]; b = buf[1]; c = buf[2];
    peri_data_available = 1;
  }
  os_delay(1);
}
}

task2
{
int a_task, b_task, c_task;    

while(1)
{
  if ( peri_data_available )
  {
    do {
        peri_data_available = 0;
        a_task = a; b_task = b; c_task = c;
    }  while (peri_data_available);
    usefull_work( a_task, b_task, c_task );
  }
  os_delay(10);
}
}


Илья

Сообщение отредактировал 501-q - Feb 3 2015, 04:23
Go to the top of the page
 
+Quote Post
Rev0.0
сообщение Feb 3 2015, 10:38
Сообщение #14


Участник
*

Группа: Участник
Сообщений: 23
Регистрация: 3-05-13
Пользователь №: 76 718



501-q, зачем вы указали цикл в task2, мне же нужны только последние данные цикл не нужен. Да и как без мьютексов, блок из трех переменных - единый, а в вашем коде задача может прервать операцию присваивания на одной из переменных и целостности блока не будет.
Go to the top of the page
 
+Quote Post
501-q
сообщение Feb 4 2015, 05:41
Сообщение #15


Участник
*

Группа: Участник
Сообщений: 38
Регистрация: 24-02-09
Из: Екатеринбург
Пользователь №: 45 296



Приветствую!

Цитата(Rev0.0 @ Feb 3 2015, 16:38) *
зачем вы указали цикл в task2, мне же нужны только последние данные цикл не нужен. Да и как без мьютексов, блок из трех переменных - единый, а в вашем коде задача может прервать операцию присваивания на одной из переменных и целостности блока не будет.

Именно для целостности блока переменных нужен цикл. Если в процессе копирования переменных в task2 сработает task1 и обновит общие переменные, то в task2 повторим копирование переменных. Обычно будет только одна итерация цикла. Поэтому и мьютексы не нужны.

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

Илья

Сообщение отредактировал 501-q - Feb 4 2015, 05:44
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 18th July 2025 - 04:10
Рейтинг@Mail.ru


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