Jump to content

    
Sign in to follow this  
pokk

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

Recommended Posts

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

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

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

    SaveConfing(&confing.var1,100);  

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

Share this post


Link to post
Share on other sites
12 minutes ago, Сергей Борщ said:

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

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

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

 

Share this post


Link to post
Share on other sites
1 hour ago, pokk said:

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

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

Share this post


Link to post
Share on other sites
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. Примеры можно найти здесь

Share this post


Link to post
Share on other sites
17 minutes ago, AlexandrY said:

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

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

 

Share this post


Link to post
Share on other sites
2 часа назад, Сергей Борщ сказал:

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

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

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

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

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

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

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

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

Share this post


Link to post
Share on other sites
37 minutes ago, jcxz said:

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

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

Share this post


Link to post
Share on other sites
3 минуты назад, pokk сказал:

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

нет. Это char volatile flag;

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

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

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

Share this post


Link to post
Share on other sites
4 hours ago, pokk said:

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

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

Share this post


Link to post
Share on other sites
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();

 

Share this post


Link to post
Share on other sites
23 minutes ago, pokk said:

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

 

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

Share this post


Link to post
Share on other sites
1 час назад, pokk сказал:

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

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

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

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

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

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

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

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

Именно так.

Share this post


Link to post
Share on other sites
4 hours ago, jcxz said:

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

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

Share this post


Link to post
Share on other sites
5 минут назад, pokk сказал:

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

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

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

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

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

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

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

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

while (1) {

  if (flag) {

    flag = 0;

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

  } else {

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

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

   }

}

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

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