1С глобальная переменная: Переменные в 1С 8.2 и 8.3

Содержание

Модуль приложения в 1С 8.3: luckyea77 — LiveJournal

Модуль приложения

В модуле приложения находятся обработчики событий, которые выполняются при запуске конфигурации и при завершении работы. Другое название данного модуля — модуль управляемого приложения. Также есть модуль обычного приложения, который используется в конфигурациях с основным режимом запуска Обычное приложение (конфигурации на обычных формах).

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

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



Перем ПеременнаяМодуляПриложения; //обычная переменная модуля Перем ГлобПеременная Экспорт; //а это глобальная переменная //данная функция будет доступна в любых клиентских модулях Функция Экспортная() Экспорт Возврат Истина; КонецФункции

Из модуля приложения можно вызывать процедуры и функции клиентских общих модулей и серверных неглобальных общих модулей с флагом ВызовСервера.

Для открытия модуля приложения нужно щелкнуть правой кнопкой по корню конфигурации и выбрать Открыть модуль приложения:

Основные события модуля приложения

ПередНачаломРаботыСистемы

Выполняется при запуске конфигурации, до открытия основного окна. Есть параметр Отказ, если установить Отказ = Истина, то программа не запустится. Основное предназначение данного события — это выполнить различные проверки (например прав доступа) и при необходимости запретить запуск программы. Также в данном событии можно инициализировать какие-нибудь глобальные переменные.

ПриНачалеРаботыСистемы

Выполняется после открытия основного окна конфигурации. Здесь уже нельзя отказаться от запуска программы. В основном его используют для открытия каких-нибудь форм при запуске конфигурации.

ПередЗавершениемРаботыСистемы

Выполняется перед завершением работы конфигурации, до закрытия основного окна. Есть 2 параметра: Отказ и ТекстПредупреждения. Если установить Отказ = Истина, то до закрытия основного окна будет выдано предупреждение «Работа в данном окне не завершена» и предложено 2 варианта: завершить работу, продолжить работу.

Процедура ПередЗавершениемРаботыСистемы(Отказ, ТекстПредупреждения) Отказ = Истина; КонецПроцедуры

Если выбрать Завершить работу, то программа будет закрыта. Если выбрать Продолжить работу, то нет.

Если заполнить параметр ТекстПредупреждения, то вместо «Работа в данном окне не завершена» будет выведен текст из данного параметра:

Процедура ПередЗавершениемРаботыСистемы(Отказ, ТекстПредупреждения) ТекстПредупреждения = "Закрыть программу?"; Отказ = Истина; КонецПроцедуры

ПриЗавершенииРаботыСистемы

Выполняется при завершении работы конфигурации, после закрытия основного окна приложения. В данном событии нельзя использовать сообщения и открытие форм. В основном используется для выполнения каких-либо действий при выходе из программы.

Серверные вызовы и открытие окон при завершении работы

В событиях ПередЗавершениемРаботыСистемы и ПриЗавершенииРаботыСистемы нельзя использовать серверные вызовы, иначе будет ошибка «Серверные вызовы при завершении работы запрещены». Также нельзя использовать открытие окон, иначе будет ошибка «Открытие окон при завершении работы запрещено».


Смотрите также:
Электронный учебник по по программированию в 1С
Рекомендации по изучению программирования 1С с нуля
Программное решение для сдачи и подготовки к экзаменам
Программирование в 1С 8.3 с нуля — краткий самоучитель
Комплексная подготовка программистов 1С:Предприятие 8.2
Сайты с уроками программирования и со справочниками
Youtube-каналы с уроками программирования
Сайты для обучения программированию
Лекции и уроки

Бесшовная интеграция 1С Документооборот и1С ERP, БП, УТ и др.

: 2 варианта реализации

Оглавление

Стандартная интеграция с 1С: Документооборот
Так в чем же проблема?
Какие есть варианты решения?
Принцип работы
Инструкция по доработке

Интеграция с 1С Документооборот: стандартная реализация

Для тех, кто ещё не сталкивался с библиотекой интеграции с 1С: Документооборот — это подсистема, внедряемая в типовые прикладные решения на базе 1С (ERP, БП, УТ и пр.) и позволяющая бесшовно интегрировать эти решения с 1С:ДО, работать пользователю в конфигурации, взаимодействуя с системой документооборота напрямую, в режиме единого окна.

При этом, в интегрируемых документах системы появляется ссылка «Документооборот», перейдя по которой можно создать или посмотреть / изменить соответствующий документ в документообороте (Рис. 1)

Рис. 1 Просмотр документа

Данное интеграционное решение очень удобно для оперативной работы с 1С: Документооборот, так как пользователю не нужно «прыгать» между двумя программами или ждать, когда созданный документ мигрирует средствами стандартных планов обмена (или не мигрирует по непонятной причине): все происходит «на лету» и результат виден сразу.

Так в чем же проблема?

А проблема в том, что зачастую, эти удобства заканчиваются, когда в 1С:ДО появляются все новые и новые виды документов, внешний вид и состав реквизитов каждого из которых значительно отличаются друг от друга. В библиотеке интеграции предусмотрена лишь одна форма для интерпретации документа ДО и её внешний вид и состав никак не зависит от настроек соответствующего документа в ДО (Рис. 2,3,4)

Рис. 2 Форма внутреннего документа в 1С Документооборот

Рис.3 Интегрированная форма в 1С ЕРП, закладка «Реквизиты»

Рис.4 Интегрированная форма в 1С ЕРП, закладка «Свойства»

Какие есть варианты решения?

ВАРИАНТ 1

Бесшовная интеграция 1С Документооборот с доработкой стандартной библиотеки

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

Однако данный вариант имеет ряд значительных недостатков:

Во — первых, это не гибкое решение, при появлении новых видов документов в ДО, придется каждый раз обращаться в конфигуратор и создавать новую форму интеграции;

Во — вторых, это значительные изменения самой библиотеки, что в дальнейшем сильно скажется на трудоёмкости проведения процедуры обновления;

ВАРИАНТ 2

Реализовать отображение внутренних документов программы 1С:Документооборот в интегрируемой системе через веб-интерфейс

В 1С есть две интересные возможности: работа с программой в веб — интерфейсе и поле html документа для отображения веб — страниц.

Отсюда второе решение, о котором и пойдёт речь в данной статье: почему бы не отобразить документ системы 1С Документооборот прямо в окне интегрируемой конфигурации?

Забегая вперед, давайте посмотрим на получившийся результат на примере бесшовной интеграции 1С:Документооборот с 1С:ERP (Рис. 5)

Рис.5 Документ 1C:ДО, открытый в 1С:ERP через веб-клиент

Принцип работы

В интегрируемой системе (далее ИС) добавим общую форму, которая будет служить «окном» в наш ДО. При открытии ИС будем загружать в эту форму 1С:Документооборот через веб-интерфейс со специальным параметром. В течении всей работы пользователя в ИС эта форма будет открыта

При переходе по ссылке «Документооборот» (см. рис. 1) на интегрируемых документах будем переопределять открытие стандартной формы интеграции на добавленную форму: будем отправлять свой запрос в ДО, используя стандартный функционал подключения библиотеки интеграции.

Данным запросом запишем в ДО в специально подготовленную таблицу (например, регистр сведений) информацию о документе (ссылку), который мы хотим открыть.

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

В это время на стороне ЕРП окно с формой, в которой открыт Документооборот активизируется и в нем отображается нужный документ.

Инструкция по доработке

Доработки на стороне 1С Документооборот:

Добавляем регистр сведений «ВнутренниеДокументыДляОткрытияИзИС«, который будет хранить ссылки на документы, открываемые пользователем на стороне ИС. Регистр независимый, непериодический. Структура регистра:

где:
ВнутреннийДокумент — СправочникСсылка.ВнутренниеДокументы
Пользователь — СправочникСсылка.Пользователи

В модуле приложения объявляем глобальную переменную:

В процедуре «ПередНачаломРаботыСистемы«, если ПараметрЗапуска = «OpenWithWeb«, то нашей глобальной переменной присваиваем значение истина и устанавливаем режим открытия окна ВстроенноеРабочееМесто:

В процедуре ПриНачалеРаботыСистемы подключаем обработчик ожидания

Данный обработчик ожидания мониторит регистр сведений «ВнутренниеДокументыДляОткрытияИзИС«. После успешного открытия документа, запись регистра сведений очищается:

В форме элемента справочника «Внутренние документы» анализируем значение глобальной переменной «ОткрытВебКлиентВ_ИС» в процедуре «ПриОткрытии«. Если значение Истина, то в документе скрываем кнопку закрытия, скрываем кнопку «Записать и закрыть«, скрываем заголовок:

делается это для того, чтобы в ИС пользователь не смог закрыть документ и чтобы заголовок документа не отображался два раза в ИС (описание доработок на стороне ИС будет ниже).

В XDTO пакете «DM» создаем два новых типа объекта: «DMRetrieveRequest_» и «DMRetrieveRespons_«. Пакет «DMRetrieveRequest_» содержит идентификатор внутреннего документа Документооборота, который открывается на стороне ИС:

Пакет «DMRetrieveRespons» пустой.

В общий модуль «ОбработкаЗапросовXDTO» добавляем ветку для обработки пакета «DMRetrieveRequest_» в функцию «ОбработатьУниверсальноеСообщение«:

Функция «ЗаписатьВРегистрСведенийДляИС«производит запись внутреннего документа, который пользователь открывает на стороне ИС:

и возвращает пакет «DMRetrieveRespons» в случае успешной записи или пакет «DMError» в случае возникновения какой либо ошибки

Доработки на стороне интегрируемой системы, на примере конфигурации 1С: ERP 2. 4:

Добавляем общую форму «ВнутреннийДокументДО_ИС«, на которую выносим поле HTML документа. При открытии формы передаем в это поле ссылку для открытия 1С Документооборот с параметром «OpenWithWeb«

В персональные настройки пользователя добавляем настройку «Отображать документы ДО через веб-интерфейс» (как это сделать, здесь описывать не будем):

Если у пользователя эта настройка установлена, то при открытии программы открывается общая форма, в которой в свою очередь, в поле HTML документа открывается окно 1С Документооборот. Реализовано через доработку модуля приложения:

Объявляется глобальная переменная «ФормаВебКлиентаДО«, которая будет хранить общую форму ФормаВебКлиентаДО_ИС с открытым Документооборотом.
В обработке «ИнтеграцияС1СДокументооборот» в формах «Задачи» и «Задачи мне» в событии открытия документа вызывается процедура «ОткрытьОбъект» общего модуля «ИнтеграцияС1СДокументооборотКлиент». Ее дорабатываем:

Процедура обработки оповещения общей формы выглядит так:

Теперь, когда мы хотим открыть документ программы 1С:Документооборот в интегрируемой конфигурации, у нас открывается веб страница с открытой программой 1С:Документооборот, в которой уже открыт документ. Работая с документом, мы работаем не в интегрируемой системе, а непосредственно в 1С:Документооборот, не используя бесшовную интеграцию.

Желаем вам быстрой и удобной интеграции 1C:Документооборот!

Можем помочь

У вас есть задачи по бесшовной интеграции 1С:ДО? Напишите нам.

Заполните анкету, мы свяжемся с вами в ближайшее время

python — Использование глобальных переменных в функции

Мы можем создать глобальную переменную с помощью следующей функции:

 def create_global_variable():
    global global_variable # сначала нужно объявить его глобальным
    # Таким образом, изменения отражаются в глобальной области видимости модуля
    global_variable = 'Фу'
 

Написание функции фактически не запускает ее код.

Итак, мы вызываем функцию create_global_variable :

 >>> create_global_variable()
 

Использование глобалов без изменений

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

Например,

 def use_global_variable():
    вернуть глобальную_переменную + '!!!'
 

и теперь мы можем использовать глобальную переменную:

 >>> use_global_variable()
'Фу !!!'
 

Изменение глобальной переменной внутри функции

Чтобы указать глобальную переменную на другой объект, вам необходимо снова использовать ключевое слово global:

 по определению change_global_variable():
    глобальная глобальная_переменная
    global_variable = 'Панель'
 

Обратите внимание, что после написания этой функции код, фактически изменяющий ее, еще не запущен:

 >>> use_global_variable()
'Фу !!!'
 

Итак, после вызова функции:

 >>> change_global_variable()
 

мы видим, что глобальная переменная была изменена. Имя global_variable теперь указывает на 'Bar' :

 >>> использовать_глобальную_переменную()
'Бар!!!'
 

Обратите внимание, что «глобальный» в Python не является действительно глобальным — он глобальный только на уровне модуля. Таким образом, он доступен только для функций, написанных в модулях, в которых он является глобальным. Функции запоминают модуль, в котором они написаны, поэтому при экспорте в другие модули они все равно ищут в модуле, в котором были созданы, глобальные переменные.

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

 по определению use_local_with_same_name_as_global():
    # Плохое имя для локальной переменной.
    global_variable = 'Баз'
    вернуть глобальную_переменную + '!!!'
>
>> use_local_with_same_name_as_global() «Баз !!!»

Но использование этой неправильно названной локальной переменной не изменяет глобальную переменную:

 >>> use_global_variable()
'Бар!!!'
 

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

Мы получаем такое же поведение в классах

Последующий комментарий спрашивает:

что делать, если я хочу создать глобальную переменную внутри функции внутри класса и хочу использовать эту переменную внутри другой функции внутри другого класса?

Здесь я демонстрирую, что мы получаем то же поведение в методах, что и в обычных функциях:

 class Foo:
    деф фу(я):
        глобальная глобальная_переменная
        global_variable = 'Фу'
класс Бар:
    полоса защиты (я):
        вернуть глобальную_переменную + '!!!'
Фу().фу()
 

А теперь:

 >>> Bar().bar()
'Фу !!!'
 

Но я бы посоветовал вместо использования глобальных переменных использовать атрибуты класса, чтобы не загромождать пространство имен модулей. Также обратите внимание, что мы не используем здесь аргументы self — это могут быть методы класса (удобно при изменении атрибута класса из обычного аргумента cls ) или статические методы (нет self или cls ).

Проблемы с глобальными переменными

4 мая 2022 г., Phillip Johnston • Последнее обновление 28 июля 2022 г.

Мы стараемся не издавать правила и указы, давая советы по программированию. У каждого решения есть компромиссы, и иногда компромиссы, которые необходимо сделать, полностью сводят на нет общие советы. Тем не менее, мы не можем игнорировать коллективный опыт всей нашей отрасли на протяжении многих десятилетий. Что делает нас мудрее тех, кто был до нас?

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

В этой статье мы обсудим проблемы с глобальными переменными, альтернативные подходы к совместному использованию данных, методы рефакторинга и рекомендации по использованию глобальных переменных.

Содержание:

  1. Задачи с глобальными переменными
  2. Альтернативы глобальным переменным
  3. Методы рефакторинга
  4. Правила использования глобальных переменных
  5. Ссылки

Проблемы с глобальными переменными

Глобальные переменные подвержены ряду проблем:

  1. Нарушает сокрытие информации
  2. Отрицает принцип открытого-закрытого
  3. Вводит неявное связывание и побочные эффекты
  4. Трудно отследить
  5. Слежка
  6. Псевдоним
  7. Условия гонки
  8. Глобальные проблемы с заказом инициализации
  9. Комментарии не помогают
  10. Трудности тестирования

Нарушает скрытие информации

Использование глобальных переменных указывает на плохую модульность. Это также нарушает принцип сокрытия информации. Реализация глобальных данных доступна для остальной части программы — нет простого способа изменить способ хранения или кодирования данных без изменения каждой ссылки на эту переменную во всей программе. Если в будущем произойдет редизайн, изменения будут распространяться по всей программе.

Отменяет принцип открытия-закрытия

Использование глобальных переменных исключает возможность применения принципа открытия-закрытия (OCP). Любой компонент, который зависит от глобальной переменной, не может быть действительно закрыт для модификаций — изменение в одном компоненте, которое приводит к неожиданному использованию переменной, нарушит работу других компонентов, использующих эту переменную.

Представляет неявное связывание и побочные эффекты

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

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

Трудно отследить

Поскольку система не обеспечивает хорошей инкапсуляции, может быть трудно понять, что именно происходит в системе. Кроме того, нет контроля доступа к глобальным переменным, а это означает, что их можно изменять где угодно — неясно, кто несет ответственность за изменение переменной.

Конечным результатом этих факторов является то, что последствия изменения не могут быть определены на месте изменения — вместо этого необходимо проанализировать все случаи использования переменной, чтобы определить эффект изменения. Побочные эффекты также могут возникать из-за того, что две разные части программы изменяют переменную в непредвиденной последовательности, потому что распределенная природа переменной затрудняет правильное обоснование ее использования. Конечно, вы можете выполнить анализ того, где записывается и читается каждая глобальная переменная, но это часто занимает много времени и чревато ошибками. Кроме того, использование псевдонимов (обсуждается ниже) повышает вероятность того, что простой поиск будет некорректным. Любое изменение глобальной переменной сделает этот анализ недействительным и потребует его повторного выполнения.

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

Затенение

Можно попасть в ситуацию, когда у вас есть «затенение глобальной переменной», что происходит, когда вы объявляете локальную переменную с тем же именем, что и глобальная переменная. Это может привести к неожиданному поведению, поскольку вы можете подумать, что изменяете глобальную переменную, когда вместо этого работаете с локальной переменной. К счастью, современные компиляторы могут генерировать предупреждение об этом, но мы работали над проектами, в которых это предупреждение не было включено, и теневое копирование происходило незаметно, что приводило к ошибочному поведению.

Псевдоним

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

Условия гонки

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

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

Проблемы порядка глобальной инициализации

В C++ порядок инициализации глобальных и файловых статических переменных является распространенным источником проблем в системе. В стандарте указано, что глобальные переменные в одном исходном файле создаются и инициализируются в том порядке, в котором они появляются в файле. Однако не гарантируется глобальный порядок в исходных файлах. Когда глобальная переменная в одном файле ссылается на глобальную переменную в другом файле, порядок инициализации может отличаться от ожидаемого, что приводит к сбою. Эти сбои могут меняться в зависимости от того, как объектные файлы связаны в сборке, что приводит к ложным проблемам, которые появляются и исчезают с течением времени.

Некоторые утверждают, что недостатки глобальных переменных можно уменьшить с помощью разумных комментариев, объясняющих назначение и операции переменной. Однако эти типы комментариев не решают проблемы с глобальными переменными. Из-за их природы вы даже можете понять, что объяснения того, что представляет собой переменная, как она используется и как к ней обращаться, совершенно неверны. Это часто может возникать из-за сложности, связанной с чтением/записью переменной в нескольких местах — например, при выполнении могут существовать тонкие условия гонки из-за характера сгенерированного кода, но они могут быть не замечены разработчиками, читающими код. . Комментарии также не решают проблему, потому что всегда существует вероятность устаревания информации из-за распределенного характера переменной.

Проблемы с тестированием

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

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

Альтернативы глобальным переменным

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

  1. Уменьшение объема
  2. Доступ к данным через интерфейсы
  3. Передача сообщений
  4. Обратные вызовы

Уменьшить область действия

Самый простой способ действий — максимально уменьшить область действия глобальной переменной. По умолчанию вы должны использовать наименьшую практическую область видимости для переменных и функций:

  • По возможности предпочитать работать с локальными данными или данными, которые передаются параметром
  • Работа с локальными статическими переменными функции (к ним нельзя получить доступ вне функции)
  • Предпочитает работать со статическими переменными файла (к ним нельзя получить доступ за пределами исходного файла)

При анализе в обратном направлении можно:

  • Изменить глобальные переменные на файловые статические переменные
  • Изменить статические переменные файла на локальные статические переменные

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

Объем глобальной переменной часто можно уменьшить, если переосмыслить организацию исходного кода. Дополнительные сведения см. в разделе «Методы рефакторинга».

Доступ к данным через интерфейсы

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

Дополнительные сведения см. в разделе «Методы рефакторинга».

Передача сообщений

Часто программное обеспечение встроенных систем использует глобальные переменные для обмена информацией между контекстами, например для чтения данных в ISR и предоставления их в основном цикле или передачи данных между несколькими потоками. Вместо использования глобальных переменных можно использовать очередь (например, для передачи сообщений, событий или новых значений данных). Такие очереди часто поставляются со многими RTOS, но их также можно создавать из кольцевых буферов. Область действия очереди может быть уменьшена, чтобы она была доступна только необходимому производителю и потребителю(ам), независимо от того, осуществляется ли она через статическую переменную файла или становится доступной путем передачи дескриптора очереди в модуль в качестве параметра функции.

Дополнительная литература

Дополнительные сведения по этой теме см. в разделе «Передача сообщений».

Обратные вызовы

Другой способ поделиться новым значением данных с заинтересованными клиентами — использовать обратные вызовы (или, в более общем смысле, шаблон Observer). Всякий раз, когда доступны новые данные, производитель может поделиться этими данными, вызвав все зарегистрированные обратные вызовы и передав новые данные по параметру.

Методы рефакторинга

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

  • Рефакторинг глобальных данных для поддержки нескольких экземпляров описывает подход к рефакторингу, который может решить общую проблему глобальных данных, заключающуюся в необходимости перехода от поддержки одного экземпляра чего-либо к поддержке нескольких экземпляров. Тот же метод можно использовать для локализации глобальных данных — сначала инкапсулируйте данные в структуру, а затем уменьшите область действия этой структуры (будь то в модуле или при передаче информации через параметры функции).
  • Better Embedded System SW: избавление от глобальных переменных описывает процесс преобразования глобальной переменной и связанных функций, которые ее используют, в единый модуль. Это предпочтительнее по ряду причин — это локализует доступ (упрощая внесение изменений и отладку), скрывает реализацию, и мы действительно можем включить многопоточность, будучи уверенными, что мы правильно заблокировали
  • Реорганизация исходного кода на основе доступа к данным
    • Общие глобальные данные можно уменьшить, переосмыслив организацию исходного кода: упорядочить исходные файлы на основе доступа к данным . Функции, изменяющие одни и те же глобальные данные, могут быть сгруппированы в одном модуле. Затем глобальная переменная может быть уменьшена до статической переменной файла, обслуживающей эту группу функций.
    • Чтобы использовать пример, данный Филом Купманом, рассмотрим переменную времени суток, которая обновляется ISR. Вы можете создать TimeOfDay.c , который содержит следующее:
      • Статическая переменная файла timeOfDay
      • Реализация функции таймера ISR
      • API для чтения времени суток (возвращает значение timeOfDay ).

Правила использования глобальных переменных

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

  • Каждая глобальная переменная или категория глобальных переменных должны быть обоснованы в соответствии с требованиями эффективного конструирования программного обеспечения, а обоснование их использования должно быть задокументировано для других разработчиков.
    • Эффективность не является причиной для использования глобальных переменных (например, «доступ к этим данным через функцию приводит к накладным расходам» редко бывает достаточным оправданием. Если это действительно то, что является узким местом вашей системы, установите более быстрый процессор.)
  • В многозадачной системе каждый глобальный объект должен быть объявлен volatile и каким-либо образом защищен (например, мьютексом в критической секции).

Когда глобальные данные используются для значения конфигурации, математической константы или другого значения, которое не изменяется во время выполнения, убедитесь, что:

  • Переменная объявлена ​​с использованием ключевого слова const для предотвращения изменений
  • Видимость ограничивается необходимостью знать, а не делает ее видимой для всей системы в общем виде globals.h Файл типа .

Ссылки

  • Глобальные переменные, признанные Вульфом и Шоу вредными

    Мы утверждаем, что нелокальные переменные являются важным фактором в программах, которые трудно понять. […] Грубо, однако, мы имеем в виду любую переменную, доступ к которой и, в частности, ее изменение на относительно большом участке текста программы.

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

  • Техника: рефакторинг глобальных данных для поддержки нескольких экземпляров
  • Better Embedded System SW: Global Variables Are Evil пример главы Фила Купмана

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

    Указатели на глобальные объекты еще более злые.

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

  • Глобальные переменные — зло! Слайды лекции Фила Купмана

    Использование глобальных переменных указывает на плохую модульность

  • Better Embedded System SW: Minimise Use of Global Variables by Phil Koopman

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

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

    Последствия:  Использование слишком большого количества глобальных переменных увеличивает сложность программного обеспечения и, как можно разумно ожидать, приведет к увеличению количества ошибок, а также затруднит правильное сопровождение кода. Можно обоснованно ожидать, что определение переменных как глобальных, которые вместо этого можно было бы определить как локальные, значительно увеличит риск неправильного использования данных в глобальном масштабе, а также затруднит отслеживание и анализ нескольких переменных, которые должны быть глобальными на законных основаниях. Короче говоря, чрезмерное использование глобальных переменных приводит к увеличению числа программных дефектов.

    Значительное меньшинство переменных (или меньше) должно быть глобальным. В идеале нулевые переменные должны быть глобальными. (Специальные глобальные переменные, такие как математические константы и информация о конфигурации, могут быть исключены из этой метрики.) Точное число зависит от системы, но ожидаемый диапазон будет от менее 1 % до, возможно, 10 % всех статически распределенных переменных (даже это вероятно, слишком высокий), с чрезвычайно сильным предпочтением нижней части этого диапазона. Можно разумно ожидать, что превышение этого диапазона приведет к увеличению числа дефектов программного обеспечения.

    Потребность в каждой глобальной переменной или категории глобальных переменных должна быть конкретно обоснована в соответствии с требованиями эффективного построения программного обеспечения. Увеличение скорости, как правило, не является достаточным оправданием, равно как и ограниченное пространство памяти.

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

    Каждая переменная должна быть объявлена ​​локально, если это возможно. Переменные, используемые набором функций в одном и том же модуле языка программирования C, должны быть объявлены как «статические» верхнего уровня в соответствующем файле .c, чтобы ограничить видимость функций, объявленных в этом файле .c. Переменные, используемые только одной функцией, должны быть объявлены внутри этой функции и, таким образом, не должны быть видны какой-либо другой функции.

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

    Еще одна причина, по которой следует избегать глобальных переменных, заключается в том, что они представляют опасность параллелизма (см. обсуждение параллелизма в следующем посте). Поскольку трудно отслеживать, какие части программы считывают и записывают глобальные данные, безопасный код должен предполагать, что другие задачи могут получить доступ к глобальным и использовать полную защиту параллелизма каждый раз, когда к глобальным обращаются. Это включает в себя как блокировку доступа к глобальному при внесении изменений, так и объявление глобального «изменчивым», чтобы гарантировать распространение любых изменений по всему программному обеспечению.

    Даже если угроз параллелизма обычно удается избежать, если глобальные переменные изменяются более чем в одном месте программы, легко получить неожиданное поведение программного обеспечения из-за того, что две части программы изменяют значения глобальных переменных в непредвиденной последовательности. Можно разумно ожидать, что это приведет к редким и малозаметным (но потенциально серьезным) дефектам параллелизма.

    Использование слишком большого количества глобальных переменных можно рассматривать как вариант спагетти-кода с потоком данных. При запутанном потоке «управления» кода (условные операторы «если» и т.п.) трудно проследить поток управления программным обеспечением. Точно так же, когда слишком много глобальных переменных, трудно отслеживать поток данных в программе — вы получаете «спагетти-данные». В обоих случаях (запутанный поток данных и запутанный поток управления) разработчики могут разумно ожидать, что спагетти-программное обеспечение будет иметь повышенный уровень программных дефектов. Чрезмерное использование глобальных переменных затрудняет модульное тестирование, поскольку требует определения и установки определенных значений во всех глобальных переменных, на которые ссылается модуль, который тестируется.

  • Better Embedded System SW: избавление от глобальных переменных Фил Купман
  • «Принцип открытого-закрытого» Роберта Мартина

    Никаких глобальных переменных — никогда.

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

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

    Опять же, в игру вступают вопросы стиля. Альтернативы использованию глобальных переменных обычно очень недороги. В этих случаях использование техники, которая рискует даже небольшим количеством закрытия, является плохим стилем по сравнению с техникой, которая не несет такого риска. Однако бывают случаи, когда удобство глобалки имеет большое значение. Общие примеры — глобальные переменные cout и cin. В таких случаях, если не нарушается принцип открытого-закрытого, то удобство может стоить нарушения стиля.

  • C++: аргумент против глобальных переменных
  • C2 Wiki: плохие глобальные переменные
  • Code Complete Стива МакКоннелла, цитируемого Купманом в Минимизируйте использование глобальных переменных

    МакКоннелл говорит: «Глобальные данные подобны любовному письму между подпрограммами — они могут быть отправлены туда, куда вы хотите, или они могут потеряться. В почте.» (МакКоннелл 1993, стр. 88). МакКоннелл также говорит: «Глобальная связь данных нежелательна, потому что связь между подпрограммами не является ни тесной, ни видимой. Эту связь так легко упустить, что ее можно назвать злобным родственником сокрытия информации — «потерей информации»» (McConnell 19).93, с. 90).

  • [решено] Когда глобальные переменные действительно считаются хорошей/рекомендуемой практикой? – Local Coder

    Глобальные переменные, как правило, плохи не из-за их производительности, они плохи, потому что в программах значительного размера сложно инкапсулировать все – существует «утечка» информации, которая часто очень затрудняет вычисление что происходит.

  • CppCoreGuidelines/CppCoreGuidelines.md на главном устройстве · isocpp/CppCoreGuidelines

    I.2: Избегайте не- const  глобальных переменных
    Причина: Не- const  глобальные переменные скрывают зависимости и делают зависимости подверженными непредсказуемым изменениям.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *