В процессе работы с торговым оборудованием, в частности с электронными весами в режиме РМК (Рабочее место кассира), программисты часто сталкиваются с проблемой «мертвого» зависания системы. Это происходит, когда функция ПолучитьВесСЭлектронныхВесов отправляет запрос драйверу оборудования, а тот, в свою очередь, не возвращает ответ из-за аппаратного сбоя, плохого контакта в COM-порту или некорректной работы USB-адаптера. Интерфейс 1С блокируется, и кассир вынужден завершать работу программы через диспетчер задач.
В данной статье мы разберем, как автоматизировать прерывание функции по истечении заданного времени (например, 3 секунды), чтобы программа продолжала работу даже при отсутствии ответа от оборудования.
Прежде чем приступать к написанию кода, проанализируем ситуацию. Зависание происходит потому, что вызов внешней компоненты драйвера весов выполняется синхронно в основном потоке интерфейса. Пока драйвер не вернет результат (вес или ошибку), поток управления не возвращается в 1С. Если внутри драйвера не настроен внутренний таймаут, ожидание может длиться бесконечно.
Рассмотрим основные способы решения этой задачи, начиная от самых современных методов платформы 1С:Предприятие 8.3 и заканчивая аппаратными настройками.
Это наиболее эффективный и правильный метод для современных конфигураций на управляемых формах. Мы выносим процедуру опроса весов в отдельный поток (фоновое задание), а в основном потоке просто ждем ответа в течение определенного времени.
Разберем по шагам, как модифицировать ваш код:
ФоновыеЗадания.ОжидатьЗавершенияВыполнения() для ограничения времени.Посмотрим на пример реализации:
// Код в модуле формы РМК
&НаКлиенте
Процедура ПолучитьВесАвтоматизировано()
// 1. Формируем параметры для фонового задания
ПараметрыЗадания = Новый Структура;
// Сюда можно добавить параметры подключения к весам
// 2. Запускаем фоновое задание
Задание = ЗапуститьФоновоеЗаданиеНаСервере(ПараметрыЗадания);
// 3. Создаем массив заданий для ожидания (метод принимает массив)
МассивЗаданий = Новый Массив;
МассивЗаданий.Добавить(Задание);
Попытка
// Ждем завершения 3 секунды
ФоновыеЗадания.ОжидатьЗавершенияВыполнения(МассивЗаданий, 3);
// Если дошли сюда, значит задание завершилось вовремя
ЗаданиеОбъект = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(Задание.УникальныйИдентификатор);
Если ЗаданиеОбъект.Состояние = СостояниеФоновогоЗадания.Завершено Тогда
// Получаем результат (например, через временное хранилище или параметры)
ОбработатьРезультатВзвешивания();
КонецЕсли;
Исключение
// Если сработал таймаут, возникнет исключение
// 4. Обязательно отменяем задание, чтобы оно не висело в памяти
Задание.Отменить();
Сообщить("Весы не ответили вовремя. Введите вес вручную.");
КонецПопытки;
КонецПроцедуры
Важный нюанс: метод ОжидатьЗавершенияВыполнения доступен в платформе, начиная с версии 8.3.13. Он позволяет избежать ручного написания циклов опроса и «пинга» состояния задания.
Если вы хотите, чтобы во время ожидания веса интерфейс РМК оставался полностью «живым» (например, кассир мог нажать кнопку «Отмена»), лучше использовать связку с обработчиком ожидания. Рассмотрим этот алгоритм подробнее:
ПодключитьОбработчикОжидания("ПроверитьСтатусФоновогоЗадания", 1).ПроверитьСтатусФоновогоЗадания проверяем состояние задания.Проанализируем преимущества: кассир видит прогресс (например, крутящийся индикатор), но программа не «замерзает», так как управление возвращается в очередь событий Windows каждую секунду.
Иногда проблему можно решить гораздо проще, не прибегая к многопоточности. Большинство внешних компонент (DLL) для весов имеют встроенные свойства таймаута. Выясним причину, по которой ваша функция ПолучитьВесСЭлектронныхВесов ждет вечно. Скорее всего, при инициализации объекта драйвера параметр Timeout установлен в значение 0 (бесконечность) или слишком большое число (30 секунд).
Рассмотрим пример настройки объекта драйвера:
// Пример настройки драйвера АТОЛ/Штрих-М
ОбъектДрайвера.Timeout = 2000; // Устанавливаем 2 секунды
Результат = ОбъектДрайвера.ПолучитьВес();
Если Результат < 0 Тогда
// Драйвер сам вернет ошибку по таймауту через 2 секунды
// 1С не зависнет, а просто перейдет в блок обработки ошибки
Сообщить(ОбъектДрайвера.ОписаниеОшибки);
КонецЕсли;
Важный совет: Проверьте настройки оборудования в самой 1С (Администрирование -> Подключаемое оборудование). Часто там есть поле «Таймаут», которое передается в драйвер при подключении.
Если вы используете переходники USB-to-COM, проблема «зависания» часто кроется в драйвере самого адаптера или настройках энергосбережения Windows. Проанализируем дополнительные шаги по стабилизации связи:
ОчиститьВнешнююКомпоненту) и повторное создание объекта при следующем обращении.Для надежной работы РМК рекомендуется комбинированный подход:
Во-первых, настройте минимально возможные таймауты (1-2 сек) непосредственно в параметрах подключения оборудования в 1С.
Во-вторых, если драйвер игнорирует настройки и продолжает вешать поток, внедрите механизм фонового задания с принудительной отменой через ОжидатьЗавершенияВыполнения или Задание.Отменить(). Это гарантирует, что работа кассира не будет прервана необходимостью перезагрузки компьютера.