Управление качеством разработки микроконтроллерных систем

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Мастер Ломастер писал(а):[добалвено позже]хотя... давайте и ваш вариант рассмотрим в вашей интерпретации - хочется посмотреть нить рассуждений.[конец добавления]
Сначала о недостатках "глобального" решения моего примера.

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

2. Доступ к ней должен быть атомарным, чтобы не нарваться на обновление в момент обращения к ней. Если переменная 32-разрядная, а МК 8-разрядный, для обеспечения атомарности нужно принять специальные меры. Каждый модуль, получающий доступ к значению таймера, должен сам реализовать эту атомарность. Если из 100 фрагментов в 99 это сделано корректно, а в одном забыли (или не знали), появится трудновоспроизводимая ошибка.

3. Предположим, требования к изделию изменились. Для некоторых новых функций точность измерения времени должна составить 100 мкс. Поэтому частоту таймера пришлось поднять с 1 кГц до 10. Придется найти все обращения к таймеру в программе и соответственно пересчитать значения.

Вот самые очевидные проблемы.
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Реклама
Поставщик валерьянки для Кота
Сообщения: 1995
Зарегистрирован: Ср май 11, 2011 21:37:45
Откуда: Цветочный город

Сообщение Мастер Ломастер »

1. это важно: возможность искажения значения "на стороне".
2. это не проблема глобальной переменной, это проблема атомарного доступа. она имеет место и для локальных переменных и т.п. что касается 99 мест - это тоже имеет лишь косвенное отношение к глобальной переменной, т.к. и для обращения к функции надо выполнить какие-то подготовительные действия, и если в 1 случае из 100 их забыли сделать - проблема та же самая.
3. предположим, доступ к таймеру скрыт в интерфейсной функции get_time(). если точность выдаваемых ею значений изменилась, придется найти все обращения к этой функции в проекте и откорректировать их. чем это лучше?

резюме: только одна проблема по настоящему является проблемой - свободный доступ отовсюду к переменной - это очень скользкое место.
битва с дураками проиграна, победители торжествуют. слава победителям!
Контактная информация:
Реклама
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Теперь вариант без глобально видимой переменной.

Вместо нее в интерфейс модуля вводится метод для доступа к значению таймера:

Код: Выделить всё

// Timer.h
#include <stdint.h>
...
uint32_t Timer_get_1ms_count(void);
...
Реализация модуля:

Код: Выделить всё

// Timer.c
#include "Timer.h"

// "спрятанная" переменная
static volatile uint32_t _tmr;

// реализация метода доступа
uint32_t Timer_get_1ms_count(void)
{
  uint32_t tmp;
  tmp = Атомарный_доступ(_tmr);
  return tmp;
}

// обработка прерывания от таймера
void TmrInt(void)
{
  ...
  ++_tmr;
  ...
}
Достоинства:

1. Значение таймера доступно только на чтение, сам счетчик локален в своем модуле. Ошибка в коде одного из клиентов не может повлиять на других, следовательно, остается локальной.

2. Атомарность один раз реализована в методе доступа. Клиент не заморачивается этими деталями.

3. Если квант таймера изменился (например, частота увеличилась в 10 раз), достаточно скорректировать ее в единственном месте (в теле метода выдачи значения счетчика мимллисеккунд Timer_get_1ms_count), поделив на 10:

Код: Выделить всё

// реализация метода доступа
uint32_t Timer_get_1ms_count(void)
{
  uint32_t tmp;
  tmp = Атомарный_доступ(_tmr);
  return tmp / 10;
}
Клиенты просто не узнают об этом изменении и не нуждаются в модификации.

Вот вкратце и все. Накладные расходы минимальны, функциональность не пострадала, несколько потенциальных ошибок исключены в принципе.
Последний раз редактировалось Goldsmith Вт авг 02, 2011 11:29:17, всего редактировалось 2 раза.
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Мастер Ломастер писал(а): 3. предположим, доступ к таймеру скрыт в интерфейсной функции get_time(). если точность выдаваемых ею значений изменилась, придется найти все обращения к этой функции в проекте и откорректировать их. чем это лучше?
Чуть опередили меня. См. предыдущий пост.

P.S. Вообще один из признаков качественного кода - это слабое "сцепление" между модулями, т.е. изменения, вносимые в программу, локальны. В нашем примере - либо поделить на 10 счетчики во всей программе, либо в единственном методе. Дело даже не в лени. Трудно согласованно менять код в разных местах программы.
Последний раз редактировалось Goldsmith Вт авг 02, 2011 11:33:41, всего редактировалось 1 раз.
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Поставщик валерьянки для Кота
Сообщения: 1995
Зарегистрирован: Ср май 11, 2011 21:37:45
Откуда: Цветочный город

Сообщение Мастер Ломастер »

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

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

ну, а теперь вернемся к моему примеру с интегралом... :)
битва с дураками проиграна, победители торжествуют. слава победителям!
Контактная информация:
Реклама
Держит паяльник хвостом
Аватара пользователя
Сообщения: 906
Зарегистрирован: Ср апр 16, 2008 13:22:54
Откуда: Приднестровье, Тирасполь

Сообщение Goodefine »

Goldsmith писал(а):Теперь вариант без глобально видимой переменной.
Такой вариант сразу вызывает вопросы.
1. Что будет если обработчик прерывания таймера вынужденно размещен в другом .с модуле? Это не надумано, ведь задач, которые используют таймер, может быть много - пусть в общем случае обработчик располагается в файле interrupt.c .
2. Значение надо иногда еще и корректировать (обнулять счетчик или флаг). Если добавить интерфейсную функцию записи, то мы получим вариант уж совсем не отличающийся по безопасности доступа от глобальной переменной. Плюсом будет только атомарность, которая, как правило заметили, напрямую к глобальным переменным не относится.
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Реклама
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Мастер Ломастер писал(а):static существует давным-давно, и важнее было бы проповедовать культуру использования этого ключевого слова, чем постоянно бороться с глобальными переменными.
Вообще антоним "глобальности" - "инкапсуляция". В языке C она имитируется через static, в других языках реализована иначе. "Проповедовать" сегодня инкапсуляцию поздновато, это давно уже аксиома для всех, кто зарабатывает на хлеб написанием кода.
Мастер Ломастер писал(а):ну, а теперь вернемся к моему примеру с интегралом... :)
От вас потребуется небольшая техническая помощь. Как я уже говорил, имел дело с Паскалем бесконечно давно, и тогдашние выхолощенные диалекты никак не годились для написания встроенного софта. Подскажите, пожалуйста, как в современных диалектах выглядит локальная в пределах модуля переменная (не локальная в процедуре/функции и не глобальная по всей программе). Помню, что такие средства были добавлены в язык еще в борландовских реализациях для MS DOS, но не помню их конкретный синтаксис.
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 1995
Зарегистрирован: Ср май 11, 2011 21:37:45
Откуда: Цветочный город

Сообщение Мастер Ломастер »

проповедовать тщательность разработки ПО тоже как бы не очень разумно, но вы же проповедуете :) то, что для одного давно пройденный этап - для другого откровение свыше. здесь очень немало лиц, для которых все описываемое в данной теме является откровением, а порой и вообще недоступно для понимания. поэтому никогда не поздно показать пользу "инкапсуляции", вот только делать это путем настойчивого вдалбливания в головы вреда глобальных переменных - не самый продуктивынй путь.

что касается помощи в моем примере, то прежде надо определиться с самим понятием глобальности переменной. я его понимаю так: глобальный - это видимый вне контектса своего основного применения. то есть static-переменная в модуле все-таки глобальная переменная этого модуля. если же считать такую переменную уже не глобальной (что формально правильно), то проблемы нет и в паскале:

Код: Выделить всё

unit my_integral;
interface
   function Integral(Sample : real): real;

implementation
var 
   Sum : real;

function Integral(Sample : real): real;
begin
   Sum := Sum + Sample;
   Integral := Sum;
end;

begin
   Sum := 0;
end;
однако, суживать понятие глобальности - это типа совать голову в песок, т.е. делать вид, что проблемы нет.
битва с дураками проиграна, победители торжествуют. слава победителям!
Контактная информация:
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

По поводу этого:
Мастер Ломастер писал(а):2. это не проблема глобальной переменной, это проблема атомарного доступа. она имеет место и для локальных переменных и т.п.
Для локальных переменных эта проблема может возникнуть лишь в пределах одного модуля, ведь за его пределами они не видны. Проблема не выходит за пределы модуля, все обращения к переменной легко найти и проверить их атомарность.

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

Если весь доступ сосредоточен через единственную функцию, достаточно обеспечить атомарность для всех внешних клиентов единственный раз.

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

Речь не о том, что какую-то задачу принципиально нельзя решить глобальными объектами. Речь о том, что многих потенциальных проблем от глобальных объектов можно избежать мизерными усилиями.
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Держит паяльник хвостом
Аватара пользователя
Сообщения: 906
Зарегистрирован: Ср апр 16, 2008 13:22:54
Откуда: Приднестровье, Тирасполь

Сообщение Goodefine »

Мастер Ломастер писал(а):.... это типа совать голову в песок, т.е. делать вид, что проблемы нет.
Даже с сужением понятия глобальности, все равно статик не решает проблемы - как я уже выше сказал - обработчик прерывания может находится в каком угодно модуле...
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Поставщик валерьянки для Кота
Сообщения: 1995
Зарегистрирован: Ср май 11, 2011 21:37:45
Откуда: Цветочный город

Сообщение Мастер Ломастер »

Goodefine писал(а):...все равно статик не решает проблемы...
так и проблемы особой нет... все есть яд и лекарство, проблема лишь в дозе :)
битва с дураками проиграна, победители торжествуют. слава победителям!
Контактная информация:
Держит паяльник хвостом
Аватара пользователя
Сообщения: 906
Зарегистрирован: Ср апр 16, 2008 13:22:54
Откуда: Приднестровье, Тирасполь

Сообщение Goodefine »

Мастер Ломастер писал(а): так и проблемы особой нет... все есть яд и лекарство, проблема лишь в дозе :)
Я тоже считаю что нет. Но пример вроде должен был показать, как избавится от внешней по отношению к модулю, глобальности во всех случаях, а как видно, мало применим в реальной жизни.
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Поставщик валерьянки для Кота
Сообщения: 1995
Зарегистрирован: Ср май 11, 2011 21:37:45
Откуда: Цветочный город

Сообщение Мастер Ломастер »

Goodefine писал(а):Но пример вроде должен был показать...
не покажет :)
предположим, я сторонник велоспорта. если я стану рассказывать о достоинствах этого вида спорта, я найду миллион положительных примеров, и на каждый найдется оппонент с достойной отповедью. так и здесь: любые доказательства вредности глобальных переменных, оператора goto и т.п. будут разбиты наголову их сторонниками. а все потому, что реально существующая проблема показана не тем боком: я должен был бы проповедовать не велоспорт конкретно, как панацею, а здоровый образ жизни, пользу физических нагрузок и т.п. - тогда число оппонентов стало бы катастрофически мизерным. и в случае с программированием следует повышать общую культуру программирования, а не указывать на частности и требовать отказа от них. по мере роста этой культуры без всякого нажима приходишь к необходимости тестирования и т.п. вещей, которые ранее казались глупостями.
типа возрастное это, как и попытки доказать вредность goto :)
битва с дураками проиграна, победители торжествуют. слава победителям!
Контактная информация:
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Мастер Ломастер писал(а):проповедовать тщательность разработки ПО тоже как бы не очень разумно, но вы же проповедуете :)
Отнюдь. Я всего лишь интересуюсь, как эту проблему решают другие. Потому что вопросов у меня пока гораздо больше, чем ответов. Особенно это касается "малого" программирования, где эти ответы сильнее запаздывают.
Мастер Ломастер писал(а):вот только делать это путем настойчивого вдалбливания в головы вреда глобальных переменных - не самый продуктивынй путь.
Зачем вдалбливать? Все, что внедряется насильно, встречает сопротивление. Просто показать проблемы от глобализации объектов, возможные альтернативы и их плюсы и минусы. Кто-то оценит и воспользуется, кто-то будет стоять на своем. В обоих случаях мой личный гешефт тождественно равен нулю.
Мастер Ломастер писал(а):что касается помощи в моем примере, то прежде надо определиться с самим понятием глобальности переменной. я его понимаю так: глобальный - это видимый вне контектса своего основного применения.
Согласен. Даже акцентируем: видимый в большей степени, чем это реально необходимо. Хотя это несколько субъективно. Объективнее будет сказать: видимый без ограничения в пределах всего приложения.
Мастер Ломастер писал(а):то есть static-переменная в модуле все-таки глобальная переменная этого модуля.
Тут не согласен. Сочетание "глобальная переменная этого модуля" противоречиво: или переменная глобальна, или это действительно переменная модуля с ограниченной видимостью. static-переменная в модуле именно потому там и находится, что она должна быть видна именно в пределах. Она полностью скрыта от остальной части кода. Статические переменные примерно эквивалентны закрытым членам класса в объектно-ориентированных языках, их нельзя отнести к глобально видимым объектам.
Мастер Ломастер писал(а):если же считать такую переменную уже не глобальной (что формально правильно), то проблемы нет и в паскале:

Код: Выделить всё

unit my_integral;
interface
   function Integral(Sample : real): real;

implementation
var 
   Sum : real;

function Integral(Sample : real): real;
begin
   Sum := Sum + Sample;
   Integral := Sum;
end;

begin
   Sum := 0;
end;
однако, суживать понятие глобальности - это типа совать голову в песок, т.е. делать вид, что проблемы нет.
Но ее в данном случае действительно нет. Переменная имеет ограниченную видимость ровно в тех пределах, в которых она обязана быть видимой для функционирования этого модуля. Ее можно инициализировать нулем, в ней можно накапливать результат. Возможно, для конкретного применения интерфейс лучше было бы разбить на две отдельные функции, одна из которых добавляет значение к сумме, а другая выдает накопленный результат, но это второстепенные детали, не имеющие отношения к проблеме глобальности.

Самое главное - никакой "посторонний" модуль не может изменить значение нашего интегратора непредсказуемым для нас образом. Например, описав локальную переменную Summ, а присвоив значение глобальной Sum, о существовании которой он и не подозревал, но которая пострадает из-за своей глобальной видимости.
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Мастер Ломастер писал(а):в случае с программированием следует повышать общую культуру программирования, а не указывать на частности и требовать отказа от них. по мере роста этой культуры без всякого нажима приходишь к необходимости тестирования и т.п. вещей, которые ранее казались глупостями.
Это совершенно верно. Но это процесс эволюционный, несколько сообщений на форуме задачу не решит. На форуме можно лишь обменяться деталями с теми, кто уже воспринял основную суть. Обучение занимает годы, и то, если есть Мастер, у которого есть чему учиться. Потому и довольствуемся отдельными проблемами, вырванными из контекста.

(Кстати, именно поэтому я не хотел здесь возвращаться к частной проблеме глобальных объектов - для ее решения нужен некоторый базис).
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Держит паяльник хвостом
Аватара пользователя
Сообщения: 906
Зарегистрирован: Ср апр 16, 2008 13:22:54
Откуда: Приднестровье, Тирасполь

Сообщение Goodefine »

Мастер Ломастер писал(а):...существующая проблема показана не тем боком: я должен был бы проповедовать не велоспорт конкретно, как панацею, а здоровый образ жизни, пользу физических нагрузок и т.п. - тогда число оппонентов стало бы катастрофически мизерным...
...типа возрастное это, как и попытки доказать вредность goto :)
Снова согласен. Но дело здесь не в сторонниках глобальных переменных или гото. Язык Си настолько близок к железу, что на некоторых уровнях уже просто невозможна дальнейшая инкапсуляция. Я сам не сторонник global variable (И goto применял лишь в самом начале знакомства с Си. ), использую их только когда не вижу альтернативы. Но кое кто позволяет себе высказывания (если интересно, могу их привести), буквально клеймящие людей, их использующих. И про "возрастное" - не поверите, но это уже отмечалось, по отношению к данной проблеме..
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Друг Кота
Аватара пользователя
Сообщения: 4468
Зарегистрирован: Вс янв 24, 2010 19:19:52
Откуда: Главный Улей России (Moscow)

Сообщение DX168B »

andrej писал(а):DX168B, попробуйте до того, как высказываться, почитать статьи по ссылкам топикстартера.
где то тут - http://club.shelek.ru/viewart.php?id=350 Вы сможете найти себя.
К Вашему огромному сожалению, я не программирую встраиваемые системы на языках высокого уровня. :))) По этому, мне эти ссылки ничего не говорят. :)
I am DX168B and this is my favourite forum on internet!
Контактная информация:
Держит паяльник хвостом
Аватара пользователя
Сообщения: 906
Зарегистрирован: Ср апр 16, 2008 13:22:54
Откуда: Приднестровье, Тирасполь

Сообщение Goodefine »

Goldsmith писал(а):....именно поэтому я не хотел здесь возвращаться к частной проблеме глобальных объектов - для ее решения нужен некоторый базис).
Что ни фраза то ни шедевр. Да какой же базис? Или вы думаете что про статик мы только от вас узнали? Да это и есть азы, а вы выдаете их за откровение. В том то и дело, что иногда и статик не поможет. Базис....
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Опытный кот
Аватара пользователя
Сообщения: 736
Зарегистрирован: Пн янв 10, 2011 03:06:36
Откуда: Ростов-на-Дону

Сообщение Goldsmith »

Goodefine писал(а):Что ни фраза то ни шедевр. Да какой же базис? Или вы думаете что про статик мы только от вас узнали?
Static - это частности. Инкапсуляция - это один из трех столпов, на которых держится объектно-ориентированное проектирование. А это и есть базис, это предмет посерьезнее отдельных ключевых слов С. (Только чур не сваливаемся в обсуждение того, что на "С без плюсов" нельзя писать в объектном стиле. Можно, и даже не слишком напряжно, но это отдельная тема).
Goodefine писал(а):Да это и есть азы, а вы выдаете их за откровение.
Я об этом с самого начала твержу - азы, о которых написаны горы учебников по проектированию ПО и на обсуждение которых не нужно тратить время. Примерно как доказывать, что земля не плоская.

Взять хотя бы буквари от "трех товарищей".
Любой дурак может писать код. Настоящий профессионал - это тот, кто способен постоянно создавать продукт высокого качества, укладываясь при этом в бюджет.
J. Ganssle
Контактная информация:
Держит паяльник хвостом
Аватара пользователя
Сообщения: 906
Зарегистрирован: Ср апр 16, 2008 13:22:54
Откуда: Приднестровье, Тирасполь

Сообщение Goodefine »

Goldsmith писал(а):Static - это частности. Инкапсуляция - это один из трех столпов, на которых держится объектно-ориентированное проектирование.
Все программирование как оно есть, состоит из частностей. Хорошо избирать стратегию проектирования и строить тактику на основе определенных принципов. Но согласитесь, что иногда есть исключения. Во всех учебниках нынче пишут, что глобальные переменные следует использовать только в самом крайнем случае. Но нигде не пишут в каких. Другими словами, если подходить по умному, необходимо взвесить все за и против и принять решение. Все что я от вас добиваюсь - это ответа, указанный случай является крайним или нет?
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»