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

Удобная модификация параметров структуры confing c зашитой

Задача такая, есть несколько обработчиков вызываемые через FREERTOS  из разных задач. В них должна происходить
модификация параметра и  запись всей структуру конфигурации в память. Из за того что обработчики вызываются  
из разных задач, что бы не было переключение контента при модификации параметра его надо заблокировать  
через mutext. Первое что приходит на ум в лоб

    xSemaphoreTake(xConfing,portMAX_DELAY);
    confing.var1=100;
    confingClcCrc();
    SaveConfing();
    xSemaphoreGive(xConfing);  

Но такой вариант не нравиться (загромождает логику).   
Потом подумал завернуть это все в функцию типа такого:

    SaveConfing(&confing.var1,100);  

В принципе, уже более понятно, но тут другая проблема вылезла, функций надо большое количество под каждый тип  
под массив, под одинарную переменную, а если надо записать больше 1  параметра в одном вызове ?
Не гонять же всю структуру в память после каждого байт.
 
В общем подскажите, как это делается что бы было удобно? Или набор функций каких используете ?  
 
Была мысль, что бы, передавать сохраняемые данные в одну задачу через очереди, а там производить, модификацию  
конфигурации + запись. Но отказался от такого нагромождения из за того что, очень малая вероятность, что два обработчика  
вызовутся одновременно.

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


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

Зачем ограждать семафором изменение параметра? Унесите семафор и confingClcCrc() внутрь SaveConfing();

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


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

12 minutes ago, Сергей Борщ said:

Зачем ограждать семафором изменение параметра?

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

Хотя да, для одного и того же параметра наврятли, но структура модифицировать из другой задачи точно может.

 

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


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

1 hour ago, pokk said:

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

Насчет малой вероятности - типичное когнитивное искажение.
Например если у вас появяться два процесса с небольшой разницей в периоде повторения, то 100% будут случаи когда один будет  вытеснять контекст другого.
Даже если сами по себе процессы будут выполняться за микросекунды. 

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


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

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. Примеры можно найти здесь

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


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

17 minutes ago, AlexandrY said:

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

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

 

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


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

2 часа назад, Сергей Борщ сказал:

Зачем ограждать семафором изменение параметра? Унесите семафор и confingClcCrc() внутрь SaveConfing();

Видимо затем, что confing у автора - общая переменная, разделяемая разными процессами (задачами). А одновременный доступ к общим переменным из разных процессов чреват.  :unknw:

1 час назад, pokk сказал:

В том то и дело, что эти процессы не сильно то и повторяющиеся, их вызывает пользователь когда нажимает кнопки в меню и в web странице.

Кроме блокирующего доступа к общей переменной, другие возможные решения:

1. Строить новый экземпляр confing (или её части) в памяти, принадлежащей конкретной задаче, а потом передавать на обработку (объединение с confing) специальной задаче. Так можно избавиться от необходимости блокирующего доступа.

2. Обработку "меню" и "действий на web-странице" делать в одной задаче. Тогда проблема отпадёт сама собой.

3. Если вся проблема только из-за необходимости атомарного доступа SaveConfing() к переменной confing по чтению, то можно вообще обойтись одним флажком занятости. Который модифицирующая функция устанавливает перед модификацией confing и сбрасывает после. И после сброса флажка она пингует задачу с функцией записи.

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


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

37 minutes ago, jcxz said:

3. Если вся проблема только из-за необходимости атомарного доступа SaveConfing() к переменной confing по чтению, то можно вообще обойтись одним флажком занятости. Который модифицирующая функция устанавливает перед модификацией confing и сбрасывает после. И после сброса флажка она пингует задачу с функцией записи.

Флаг занятости, это же mutex?   
А зачем выделять функцию записи в отдельную задачу?

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


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

3 минуты назад, pokk сказал:

Флаг занятости, это же mutex?

нет. Это char volatile flag;

3 минуты назад, pokk сказал:

А зачем выделять функцию записи в отдельную задачу?

Затем что задачи-клиенты - модифицируют confing, а задача-сервер - записывает содержимое confing куда-то.

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


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

4 hours ago, pokk said:

Не гонять же всю структуру в память после каждого байт.

Почему бы и нет? Нормальная практика. Весь процес займет максимум десяток миллисекунд.
Тик операционки дольше длится.
Экономить тут время никакого смысла нет. 
Параметры еще и сериализовать можно в JSON, чтобы легко читалось и передавалось. 
Для записи во Flash надо стирать блоками, потом CRC блока конфигурации же тоже надо писать в отдельное место. 
Короче, каждый раз писать весь блок данных гораздо  удобнее чем возиться с каждым байтом.  

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


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

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();

 

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


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

23 minutes ago, pokk said:

на такой случий надо отдельные функции модификации городить

 

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

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


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

1 час назад, pokk сказал:

А можно по подробнее как это используеться? Если использовать в лоб то это как то так

Примерно так (если это Вы описали серверную задачу, записывающую данные из confing куда-то).

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

1 час назад, pokk сказал:

не вижу чем отличаеться от mutex, он даже проше. 

Странно что не видите... :unknw: И кто говорил про "проще"? Какой подход применить - выбирает разработчик, основываясь на ТЗ. А плюс 3-го варианта: неблокирующая модификация параметров в confing. Что может быть очень важным, особенно если выполнение SaveConfing() занимает заметное время.

1 час назад, pokk сказал:

А в чем преимущество такого разделение ? Что задачи клиенты не будут подтупливать на момент записи ?

Именно так.

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


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

4 hours ago, jcxz said:

Примерно так (если это Вы описали серверную задачу, записывающую данные из confing куда-то).

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

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


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

5 минут назад, pokk сказал:

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

Зачем ждать??? :wacko2: Клиент не должен ничего ждать.

Ну как ещё объяснить? Вроде всё до примитивного просто:

Клиент (пишущий данные в confing):

1. Модифицирует confing.

2. Устанавливает flag = 1.

3. Пингует сервер (посылает ему сообщение в мэйл-бокс).

Сервер (куда-то записывающий содержимое confing):

while (1) {

  if (flag) {

    flag = 0;

    куда_записывает_содержимое_confing;

  } else {

     ждёт_майл-бокса;

     сброс_сигнального_состояния_мэйл-бокса;

   }

}

Всё! Очень просто! Клиент не ждёт. Клиентов может быть много. Клиенты работают без тормозов.

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


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

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

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

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

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

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

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

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

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

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