pokk 0 Posted July 7, 2020 · Report post Задача такая, есть несколько обработчиков вызываемые через FREERTOS из разных задач. В них должна происходить модификация параметра и запись всей структуру конфигурации в память. Из за того что обработчики вызываются из разных задач, что бы не было переключение контента при модификации параметра его надо заблокировать через mutext. Первое что приходит на ум в лоб xSemaphoreTake(xConfing,portMAX_DELAY); confing.var1=100; confingClcCrc(); SaveConfing(); xSemaphoreGive(xConfing); Но такой вариант не нравиться (загромождает логику). Потом подумал завернуть это все в функцию типа такого: SaveConfing(&confing.var1,100); В принципе, уже более понятно, но тут другая проблема вылезла, функций надо большое количество под каждый тип под массив, под одинарную переменную, а если надо записать больше 1 параметра в одном вызове ? Не гонять же всю структуру в память после каждого байт. В общем подскажите, как это делается что бы было удобно? Или набор функций каких используете ? Была мысль, что бы, передавать сохраняемые данные в одну задачу через очереди, а там производить, модификацию конфигурации + запись. Но отказался от такого нагромождения из за того что, очень малая вероятность, что два обработчика вызовутся одновременно. Quote Ответить с цитированием Share this post Link to post Share on other sites
Сергей Борщ 0 Posted July 7, 2020 · Report post Зачем ограждать семафором изменение параметра? Унесите семафор и confingClcCrc() внутрь SaveConfing(); Quote Ответить с цитированием Share this post Link to post Share on other sites
pokk 0 Posted July 7, 2020 · Report post 12 minutes ago, Сергей Борщ said: Зачем ограждать семафором изменение параметра? Что бы корректно произошла модификация параметра, ведь его может модифицировать другая задача. Хотя да, для одного и того же параметра наврятли, но структура модифицировать из другой задачи точно может. Quote Ответить с цитированием Share this post Link to post Share on other sites
AlexandrY 0 Posted July 7, 2020 · Report post 1 hour ago, pokk said: Но отказался от такого нагромождения из за того что, очень малая вероятность, что два обработчика вызовутся одновременно. Насчет малой вероятности - типичное когнитивное искажение. Например если у вас появяться два процесса с небольшой разницей в периоде повторения, то 100% будут случаи когда один будет вытеснять контекст другого. Даже если сами по себе процессы будут выполняться за микросекунды. Quote Ответить с цитированием Share this post Link to post Share on other sites
Grigorij 0 Posted July 7, 2020 · Report post 2 hours ago, pokk said: В принципе, уже более понятно, но тут другая проблема вылезла, функций надо большое количество под каждый тип под массив, под одинарную переменную, а если надо записать больше 1 параметра в одном вызове ? Если речь именно про ANSI C, то можно: Вариант 1. 2 hours ago, pokk said: В принципе, уже более понятно, но тут другая проблема вылезла, функций надо большое количество под каждый тип под массив, под одинарную переменную, а если надо записать больше 1 параметра в одном вызове ? Если речь именно про ANSI C, то можно: Вариант 1. случайно отправил раньше времени, продолжение... Вариант 2. Сделать что-то типа такого: enum { CONFIG_FIELD_1, CONFIG_FIELD_2, } void SaveConfig(int type, void * value) { // забираем семафор switch (type) { case CONFIG_FIELD_1: config.var1 = *((int *)value); break; case CONFIG_FIELD_2: config.var2 = *((double *)value); break; } // сохраняем все // отдаем семафор } // где-нибудь в коде int newValue = 5; SaveConfig(CONFIG_FIELD_2, (void *)&newValue); Вариант 3. Для каждого типа данных сделать свои функции Ну и наверняка можно еще что-нибудь придумать, так как выше - это первое что пришло в на ум из того, что сам использовал в коде в разное время. Все зависит от вам и вашей программы, т.к. совсем универсального решения нет. и редактирование нормально не работает. Вариант 1. Это посмотреть на va_start, va_list, va_end. Примеры можно найти здесь Quote Ответить с цитированием Share this post Link to post Share on other sites
pokk 0 Posted July 7, 2020 · Report post 17 minutes ago, AlexandrY said: Насчет малой вероятности - типичное когнитивное искажение. Например если у вас появяться два процесса с небольшой разницей в периоде повторения В том то и дело, что эти процессы не сильно то и повторяющиеся, их вызывает пользователь когда нажимает кнопки в меню и в web странице. По этому и решил сразу же в этих обработчиках сделать запись конфигурации в память(внешнуюю), а если все таки наложаться, то по семафором должно все разрулиться. Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted July 7, 2020 · Report post 2 часа назад, Сергей Борщ сказал: Зачем ограждать семафором изменение параметра? Унесите семафор и confingClcCrc() внутрь SaveConfing(); Видимо затем, что confing у автора - общая переменная, разделяемая разными процессами (задачами). А одновременный доступ к общим переменным из разных процессов чреват. 1 час назад, pokk сказал: В том то и дело, что эти процессы не сильно то и повторяющиеся, их вызывает пользователь когда нажимает кнопки в меню и в web странице. Кроме блокирующего доступа к общей переменной, другие возможные решения: 1. Строить новый экземпляр confing (или её части) в памяти, принадлежащей конкретной задаче, а потом передавать на обработку (объединение с confing) специальной задаче. Так можно избавиться от необходимости блокирующего доступа. 2. Обработку "меню" и "действий на web-странице" делать в одной задаче. Тогда проблема отпадёт сама собой. 3. Если вся проблема только из-за необходимости атомарного доступа SaveConfing() к переменной confing по чтению, то можно вообще обойтись одним флажком занятости. Который модифицирующая функция устанавливает перед модификацией confing и сбрасывает после. И после сброса флажка она пингует задачу с функцией записи. Quote Ответить с цитированием Share this post Link to post Share on other sites
pokk 0 Posted July 7, 2020 · Report post 37 minutes ago, jcxz said: 3. Если вся проблема только из-за необходимости атомарного доступа SaveConfing() к переменной confing по чтению, то можно вообще обойтись одним флажком занятости. Который модифицирующая функция устанавливает перед модификацией confing и сбрасывает после. И после сброса флажка она пингует задачу с функцией записи. Флаг занятости, это же mutex? А зачем выделять функцию записи в отдельную задачу? Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted July 7, 2020 · Report post 3 минуты назад, pokk сказал: Флаг занятости, это же mutex? нет. Это char volatile flag; 3 минуты назад, pokk сказал: А зачем выделять функцию записи в отдельную задачу? Затем что задачи-клиенты - модифицируют confing, а задача-сервер - записывает содержимое confing куда-то. Quote Ответить с цитированием Share this post Link to post Share on other sites
AlexandrY 0 Posted July 7, 2020 · Report post 4 hours ago, pokk said: Не гонять же всю структуру в память после каждого байт. Почему бы и нет? Нормальная практика. Весь процес займет максимум десяток миллисекунд. Тик операционки дольше длится. Экономить тут время никакого смысла нет. Параметры еще и сериализовать можно в JSON, чтобы легко читалось и передавалось. Для записи во Flash надо стирать блоками, потом CRC блока конфигурации же тоже надо писать в отдельное место. Короче, каждый раз писать весь блок данных гораздо удобнее чем возиться с каждым байтом. Quote Ответить с цитированием Share this post Link to post Share on other sites
pokk 0 Posted July 7, 2020 · Report post 28 minutes ago, jcxz said: нет. Это char volatile flag; А можно по подробнее как это используеться? Если использовать в лоб то это как то так char volatile flag; void ModConfing(void){ //------------------------------------ while(1){ // ожидаем флаг if(flag==1){ break; }else{ taskYIELD(); } } //------------------------------------ //изменение конфигурации //------------------------------------ flag=0; } не вижу чем отличаеться от mutex, он даже проше. 29 minutes ago, jcxz said: Затем что задачи-клиенты - модифицируют confing, а задача-сервер - записывает содержимое confing куда-то. А в чем преимущество такого разделение ? Что задачи клиенты не будут подтупливать на момент записи ? 24 minutes ago, AlexandrY said: Короче, каждый раз писать весь блок данных гораздо удобнее чем возиться с каждым байтом. Это да запись идет всем блоком, я про такой момент ModAndSaveConfing(VAR1,100); ModAndSaveConfing(VAR2,100); ModAndSaveConfing(VAR3,100); на такой случий надо отдельные функции модификации городить confing.var1=100; confing.var2=200; confing.var3=300; SaveConfing(); Quote Ответить с цитированием Share this post Link to post Share on other sites
AlexandrY 0 Posted July 7, 2020 · Report post 23 minutes ago, pokk said: на такой случий надо отдельные функции модификации городить Почему бы и не нагородить? Используейте возможности редакторов по блочному редактированию. Я никогда не торможу если надо написать несколько десятков почти одинаковых функций. Они пушутся блочно и в одну строку, рефакторить их тоже очень просто. Но заметно упрощается отладка таких функций, по сравнению с шаблонами, макросами или некими итеративными методами. Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted July 7, 2020 · Report post 1 час назад, pokk сказал: А можно по подробнее как это используеться? Если использовать в лоб то это как то так Примерно так (если это Вы описали серверную задачу, записывающую данные из confing куда-то). Только ждать (серверной задаче) лучше на каком-нить объекте синхронизации, типа майл-бокса. И флаг она должна сбрасывать до записи(!), а не после. 1 час назад, pokk сказал: не вижу чем отличаеться от mutex, он даже проше. Странно что не видите... И кто говорил про "проще"? Какой подход применить - выбирает разработчик, основываясь на ТЗ. А плюс 3-го варианта: неблокирующая модификация параметров в confing. Что может быть очень важным, особенно если выполнение SaveConfing() занимает заметное время. 1 час назад, pokk сказал: А в чем преимущество такого разделение ? Что задачи клиенты не будут подтупливать на момент записи ? Именно так. Quote Ответить с цитированием Share this post Link to post Share on other sites
pokk 0 Posted July 7, 2020 · Report post 4 hours ago, jcxz said: Примерно так (если это Вы описали серверную задачу, записывающую данные из confing куда-то). Вообще то нет, это я описал функцию модификацию параметра на клиенте. Если флаг был сброшен, то модифицируем параметр, иначе ждем когда флаг сброситься. Quote Ответить с цитированием Share this post Link to post Share on other sites
jcxz 0 Posted July 7, 2020 · Report post 5 минут назад, pokk сказал: Вообще то нет, это я описал функцию модификацию параметра на клиенте. Если флаг был сброшен, то модифицируем параметр, иначе ждем когда флаг сброситься. Зачем ждать??? Клиент не должен ничего ждать. Ну как ещё объяснить? Вроде всё до примитивного просто: Клиент (пишущий данные в confing): 1. Модифицирует confing. 2. Устанавливает flag = 1. 3. Пингует сервер (посылает ему сообщение в мэйл-бокс). Сервер (куда-то записывающий содержимое confing): while (1) { if (flag) { flag = 0; куда_записывает_содержимое_confing; } else { ждёт_майл-бокса; сброс_сигнального_состояния_мэйл-бокса; } } Всё! Очень просто! Клиент не ждёт. Клиентов может быть много. Клиенты работают без тормозов. Quote Ответить с цитированием Share this post Link to post Share on other sites