Отправьте статью сегодня! Журнал выйдет ..., печатный экземпляр отправим ...
Опубликовать статью

Молодой учёный

Применение метода Monkey Patching для синхронизации доступа к последовательному порту

Информационные технологии
16.05.2026
3
Поделиться
Аннотация
В статье рассматривается проблема синхронизации параллельного доступа к последовательному порту UART при автоматизированном тестировании встраиваемых систем. Предложено решение на основе метода Monkey Patching с использованием реентерабельной блокировки (RLock). Приведены результаты экспериментальной проверки на реальном устройстве.
Библиографическое описание
Миронов, А. В. Применение метода Monkey Patching для синхронизации доступа к последовательному порту / А. В. Миронов. — Текст : непосредственный // Молодой ученый. — 2026. — № 20 (623). — С. 39-41. — URL: https://moluch.ru/archive/623/136768.


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

Особенность работы с UART заключается в том, что физический канал является последовательным и не поддерживает мультиплексирование запросов [1]. Если один поток отправляет команду и ожидает ответа, а второй поток в этот же момент начинает свою операцию, ответы перемешиваются, протокол обмена разрушается, а данные становятся нечитаемыми.

Классическое решение — синхронизировать все операции с портом через блокировку (mutex/lock), захватывая её перед отправкой команды и освобождая после получения ответа. Однако на практике библиотека, предоставляющая доступ к порту, может не иметь встроенной синхронизации, а её исходный код может быть недоступен или экономически нецелесообразно изменять.

В этой ситуации метод Monkey Patching позволяет модифицировать поведение библиотечных классов во время выполнения программы, «оборачивая» проблемные методы в критическую секцию без изменения исходного кода библиотеки [2].

Постановка проблемы. Имеется класс LinuxTerminal (внутренняя библиотека serterm), предоставляющий два метода для работы с UART:

— run(cmd): отправляет команду, ожидает приглашение командной строки, возвращает вывод;

— log_in(): выполняет процедуру входа в систему (отправляет логин/пароль, обрабатывает приглашения).

Внутренняя реализация такова, что log_in() напрямую обращается к порту через self.tty.write() и self.wait_for_string(), не используя метод run(). Это создаёт две проблемы:

  1. Если синхронизировать только run(), вызов log_in() из другого потока всё равно создаст коллизию.
  2. Метод log_in() внутри себя вызывает self.run(«dmesg -n1") — то есть при синхронизации возникает вложенный вызов.

При использовании обычной блокировки (threading.Lock) вложенный вызов приведёт к взаимной блокировке (deadlock): поток уже удерживает блокировку и пытается захватить её повторно.

Предлагаемое решение. Monkey Patching позволяет подменить методы run() и log_in() в момент запуска программы, не изменяя исходный код библиотеки.

Реентерабельная блокировка RLock допускает повторный захват тем же потоком, решая проблему вложенного вызова run() внутри log_in().

Декоратор functools.wraps сохраняет метаданные исходной функции (__name__, __doc__), что важно для работы инструментов отладки [3].

Код реализации на языке python представлен в листинге (рис. 1):

Листинг. Синхронизация доступа к UART через Monkey Patching

Рис. 1. Листинг. Синхронизация доступа к UART через Monkey Patching

Представлена диаграмма последовательности, иллюстрирующая взаимодействие потоков при синхронизированном доступе к UART на рис. 2.

Диаграмма последовательности синхронизации доступа к UART

Рис. 2. Диаграмма последовательности синхронизации доступа к UART

Экспериментальная проверка

Корректность работы проверялась на реальном устройстве, подключённом через USB-UART переходник. Управляющий компьютер с ОС Rocky Linux 9.6. Тестовый сценарий: одновременный запуск двух потоков, один из которых вызывает run() с короткой командой (hostname), второй — log_in().

Без синхронизации: наблюдались ошибки выполнения команд с кодом возврата 130 (процесс убит сигналом SIGINT). Служебные символы от log_in() (Ctrl+C) прерывали команду, выполняемую другим потоком.

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

Для коротких команд (dmesg, cat, echo, hostname) решение работает стабильно.

Ограничения метода

При работе с длительными командами, генерирующими большой объём вывода (stress-ng), наблюдаются единичные сбои в момент завершения теста. Причина не в методе синхронизации, а в фундаментальных ограничениях драйвера USB-to-UART в ядре Linux и библиотеки pySerial: синхронизация на уровне Python не гарантирует атомарности операций на уровне драйвера

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

Заключение

В работе рассмотрена проблема синхронизации параллельного доступа к последовательному порту UART. Предложено решение на основе метода Monkey Patching с использованием реентерабельной блокировки RLock. Основные результаты:

— Показано, как динамическая подмена методов библиотечного класса позволяет внедрить синхронизацию без изменения исходного кода.

— Обоснован выбор RLock вместо Lock для корректной обработки вложенных вызовов.

— Экспериментально подтверждена работоспособность метода для коротких команд.

— Выявлены ограничения, связанные с драйверным уровнем, и предложены пути их преодоления.

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

Литература:

1. Петров А. А. Протокол передачи данных для UART / Достижения науки и образования. — 2016. — № 1 (2). — С. 9–10.

2. Столяров А. В., Французов О. Г., Аникина А. С. Чистая компиляция как парадигма программирования / Труды ИСП РАН. — 2018. — Т. 30, вып. 2. — С. 7–24.

3. Pilgrim M. Dive Into Python 3. — Apress, 2009. — 360 p.

Можно быстро и просто опубликовать свою научную статью в журнале «Молодой Ученый». Сразу предоставляем препринт и справку о публикации.
Опубликовать статью
Молодой учёный №20 (623) май 2026 г.
Скачать часть журнала с этой статьей(стр. 39-41):
Часть 1 (стр. 1-73)
Расположение в файле:
стр. 1стр. 39-41стр. 73

Молодой учёный