Rev0.0 0 30 января, 2015 Опубликовано 30 января, 2015 (изменено) · Жалоба Привет! Вот мучаюсь и все тут, нужен свежий взгляд. Ниже привел псевдокод, который по моему мнению должен нормально работать. Имеем некоторую 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); } } Изменено 30 января, 2015 пользователем Rev0.0 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 122 30 января, 2015 Опубликовано 30 января, 2015 · Жалоба покритикуйте, пожалуйста.А почему вторая задача должна просыпаться каждый тик и проверять переменную? Неужели в вашей ОС нет средства сигнализации вроде флага? Чтобы вторая задача ушла в ожидание этого флага и проснулась только тогда, когда первая задача этот флаг просигналит? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 30 января, 2015 Опубликовано 30 января, 2015 · Жалоба Вот так надо делать: 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); } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 122 30 января, 2015 Опубликовано 30 января, 2015 · Жалоба Вот так надо делать:И что мы получили? Высокоприоритетная задача вынуждена ждать, пока низкоприоритетная задача отпустит mutex, хотя этот mutex ей для возобновления работы не нужен совсем. Тогда уж запихнуть все тело второй задачи в первую, эффект будет таким же, плюс экономия на стеке второй задачи и времени на переключение между ними. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 30 января, 2015 Опубликовано 30 января, 2015 · Жалоба И что мы получили? Высокоприоритетная задача вынуждена ждать, пока низкоприоритетная задача отпустит mutex, хотя этот mutex ей для возобновления работы не нужен совсем. Тогда уж запихнуть все тело второй задачи в первую, эффект будет таким же, плюс экономия на стеке второй задачи и времени на переключение между ними. Тут как ни крути абсурд будет по причине os_delay в обоих задачах. А я просто привел к виду принятому в RTOS. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rev0.0 0 2 февраля, 2015 Опубликовано 2 февраля, 2015 · Жалоба Сергей Борщ Ах да, забыл сказать, что task2 нельзя делать ожидающей, задумано так, что она должна работать каждый тик, поэтому лишние переключения нежелательны. Также нежелательно юзать мьютексы каждый раз при входе в задачу, т.к. они довольно ресурсоемки да и задачи выполняют еще какой-то код помимо кода обмена данными. По этим причинам у меня и возникла идея проверять флаг каждый тик и затем если флаг TRUE, то тогда уже используем лок мьютексом. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 2 февраля, 2015 Опубликовано 2 февраля, 2015 · Жалоба Также нежелательно юзать мьютексы каждый раз при входе в задачу, т.к. они довольно ресурсоемки да и задачи выполняют еще какой-то код помимо кода обмена данными. Самый ресурсоемкий в ваших примерах это вызов os_delay. На все остальное после этого можно не обращать внимания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rev0.0 0 2 февраля, 2015 Опубликовано 2 февраля, 2015 (изменено) · Жалоба Самый ресурсоемкий в ваших примерах это вызов os_delay. На все остальное после этого можно не обращать внимания. В смысле? Если мне нужно чтобы каждая задача выполнялась периодически, одна с периодом 1 мс, другая 10 мс, третья 100 мс, все задачи с разным приоритетом. Как вы это сделаете? os_delay как раз и нужна для того, чтобы когда высокоприоритетная задача отработала другие имели возможность тоже сделать это. Иначе вся ОС без os_delay будет работать в бесконечном цикле только в одной задаче с самым высоким приоритетом. Изменено 2 февраля, 2015 пользователем Rev0.0 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 122 2 февраля, 2015 Опубликовано 2 февраля, 2015 · Жалоба Ах да, забыл сказать, что task2 нельзя делать ожидающей, задумано так, что она должна работать каждый тик, поэтому лишние переключения нежелательны.Недопонял. Ну и что, что каждый тик? Все равно выполняя свой os_delay() вы вызываете переключение. Вот только момент возврата из os_delay() и начала полезной работы у вас получился никак не связан с моментом готовности данных. Также нежелательно юзать мьютексы каждый раз при входе в задачу, т.к. они довольно ресурсоемки да и задачи выполняют еще какой-то код помимо кода обмена данными.Опять не вижу связи. Если вы используете мутех при входе в задачу - задача будет ждать, даже если этот мутех ей сейчас нафиг не нужен. Я не знаю, что у вас за ОС, но мне кажется, что тут нужен не мутех, тут нужно оформить a, b, c в виде сообщения и это сообщение послать задаче 2. Возможно через очередь сообщений, а возможно достаточно и вырожденной очереди из одного сообщения. И задача 2 должна ждать появления этого сообщения. Возможно ожидать с таймаутом в один тик. А возможно надо разделить на две задачи ту работу, которую задача2 выполняет по приходу данных и ту работу, которую она должна выполнять периодически. В смысле? Если мне нужно чтобы каждая задача выполнялась периодически, одна с периодом 1 мс, другая 10 мс, третья 100 мс, все задачи с разным приоритетом. Как вы это сделаете?В вашей реализации одна задача будет выполняться с периодом 1 мс + некоторое время на ее выполнение + некоторое время на выполнение других задач, вторая - с периодом 10 мс + некоторое время, третья - 100 мс + некоторое заранее неизвестное время. Иначе вся ОС без os_delay будет работать в бесконечном цикле только в одной задаче с самым высоким приоритетом.Значит у вас что-то не так с архитектурой программы. Потому что правильно спроектированная программа с ОС все свободное время крутится в цикле задачи с наименьшим приоритетом (IdleTask), а все остальные задачи в свободное время ждут появления запускающего их события. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rev0.0 0 2 февраля, 2015 Опубликовано 2 февраля, 2015 · Жалоба Может быть я задачу как-то непонятно описал. Я же просто привел вариант когда нужно в задаче выполнять периодически действия - как вы это сделаете без os_delay? Аппаратный таймер, который шлет задаче семафор? Да, можно, но вопрос не в этом. Как вы строите архитектуру с RTOS - все задачи чего-то ждут? У меня в проекте 10 задач и некоторые ждут, а некоторые периодически выполняются. Тем задачам, что выполняются периодически нужна связь с ожидающими. Про очередь - хорошая идея, но как я писал выше мне нужны только последние данные - нет смысла в очереди. Тем более мне нужна очередь с нулевым временем ожидания. Кстати для решения того, что вы описали с нечетким периодом выполнения задач в FreeRTOS, например, есть vTaskDelayUntil. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 2 февраля, 2015 Опубликовано 2 февраля, 2015 · Жалоба Я же просто привел вариант когда нужно в задаче выполнять периодически действия - как вы это сделаете без os_delay? Используются сервисы ожидания с таймаутом. xEventGroupWaitBits с указанием xTicksToWait Но лучше создать отдельную задачу для строго периодических действий. Кстати, во Free RTOS хорошо написано почему vTaskDelay нельзя использовать для периодических задач. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Timmy 1 2 февраля, 2015 Опубликовано 2 февраля, 2015 · Жалоба Привет! Вот мучаюсь и все тут, нужен свежий взгляд. Ниже привел псевдокод, который по моему мнению должен нормально работать. Имеем некоторую RTOS и 2 задачи для простоты. Задача task1 имеет приоритет выше, чем task2. Задача task1 висит в ожидании данных от некоторой периферии. Задача task2 должна принимать ПОСЛЕДНИЕ данные от task1, т.е если задача task1 получила скажем 10 буферов данных, то нам нужен в task2 только последний буфер, остальные можем безболезненно потерять (т.е. очередь не нужна). Важное условие - код task2 должен выполняться как можно быстрее, поэтому я мьютекс поместил внутрь опроса флага, т.е. чтобы данные блокировались только когда они пришли, а не каждый цикл выполнения task2. Прав ли я с таким кодом, покритикуйте, пожалуйста. Циклический опрос следует применять только в исключительных ситуациях. В вашем случае task2 может непрерывно спать до пробуждения со стороны task1 в момент поступления новых данных. Для пробуждения можно в завимости от OS и ситуации использовать mailbox, semaphore, event и т.п. И, похоже, вы хотите выкидывать часть входных данных, если они поступают слишком быстро(более одного сэмпла в миллисекунду), но не объявили эту цель в явном виде, и не описали условие выкидывания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
501-й 0 3 февраля, 2015 Опубликовано 3 февраля, 2015 (изменено) · Жалоба Приветствую. Код нормальный. Только, думается мне, для этого примера пауза во втором потоке должна быть больше, чем в первом. Ну и я бы еще флаги менял по-другому. И можно без мьютексов. Привет! Вот мучаюсь и все тут, нужен свежий взгляд. Ниже привел псевдокод, который по моему мнению должен нормально работать. Имеем некоторую 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); } } Илья Изменено 3 февраля, 2015 пользователем 501-q Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rev0.0 0 3 февраля, 2015 Опубликовано 3 февраля, 2015 · Жалоба 501-q, зачем вы указали цикл в task2, мне же нужны только последние данные цикл не нужен. Да и как без мьютексов, блок из трех переменных - единый, а в вашем коде задача может прервать операцию присваивания на одной из переменных и целостности блока не будет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
501-й 0 4 февраля, 2015 Опубликовано 4 февраля, 2015 (изменено) · Жалоба Приветствую! зачем вы указали цикл в task2, мне же нужны только последние данные цикл не нужен. Да и как без мьютексов, блок из трех переменных - единый, а в вашем коде задача может прервать операцию присваивания на одной из переменных и целостности блока не будет. Именно для целостности блока переменных нужен цикл. Если в процессе копирования переменных в task2 сработает task1 и обновит общие переменные, то в task2 повторим копирование переменных. Обычно будет только одна итерация цикла. Поэтому и мьютексы не нужны. Вот если бы переменных было много, чтобы работа с мьютексами была бы дешевле копирования массива, то тогда можно применять мьютекс. Кроме того, если бы передача данных была двунаправленная, то мьютекс стал бы обязательным. Илья Изменено 4 февраля, 2015 пользователем 501-q Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться