PySide 기반 데스크탑 애플리케이션을 개발하면서 COM 포트 연결 과정에서 발생하는 지연 문제 → 특히 블루투스 포트 연결 시 OS 차원의 블로킹(blocking)으로 인해 전체 초기화 시간이 크게 지연되는 현상을 해결하고자 하였다.
문제 상황
애플리케이션이 실행되면 여러 장비들과 COM 포트를 통해 연결을 시도한다. 이 과정에서 일반 COM 포트는 빠르게 응답하지만, 블루투스 COM 포트는 연결 실패 시에도 OS 레벨에서 약 5초간 블로킹되어 예외를 던지게 되며, 이는 파이썬 내부에서 해결하기 애매한 상황이였다.
실제 측정 시간 (예시)
장비1 initialization took 3.79 seconds
장비2 connection took 5.27 seconds
장비3 connection took 5.20 seconds
장비4 connection took 5.18 seconds
장비 하나당 약 5초의 지연이 발생하며, 초기화에 최대 15~20초가 소요됨
시도한 해결 방법
1. 타이머 방식 도입 (실패)
처음에는 연결 함수에 타이머를 설정하여 일정 시간이 초과되면 실패로 처리하는 방식으로 접근하였다. 그러나 PySide에서 제공되는 QTimer를 사용하여야하며, 이때 타이머도 메인 스레드에서 동작하기 때문에, 포트 연결 과정에서 블로킹이 발생하면 타이머 자체도 멈추는 문제가 발생했다.
2. 스레드 분리 방식 (성공)
해결을 위해 타이머는 메인 스레드에서, 포트 동작 확인은 서브 스레드에서 동작하도록 분리하였다.
구조 요약
- AlivePortWorker 클래스를 생성하여 각 포트 상태를 확인하는 스레드를 실행
- 메인 스레드에서 타이머를 통해 연결 시도 시간을 제한
일정 시간 내 응답이 없으면 timeout 이벤트 발생 → 해당 포트를 사용불가로 분류
- 성공한 포트에 대해서만 기존의 로직에 적용되어 장비연결을 진행하게됨.
sequenceDiagram
participant MainThread
participant AlivePortWorker
participant OS
MainThread->>AlivePortWorker: 스레드 시작 및 포트 연결 요청
AlivePortWorker->>OS: COM 포트 연결 시도
Note right of OS: 블루투스 포트는 5초간 응답 없음
MainThread-->>AlivePortWorker: 타이머 timeout 이벤트 발생
MainThread->>AlivePortWorker: quit() 호출
AlivePortWorker-->>OS: 연결 응답 완료 후 종료 처리
OS-->>AlivePortWorker: 연결 실패 응답
AlivePortWorker-->>MainThread: 종료 응답 처리
스레드 메모리 문제
문제 1: 고아 객체로 인한 강제 종료
self.thread = QThread()
if timeout:
self.thread.quit()
self.thread = None # 참조 해제 → 문제 발생
스레드가 아직 종료되지 않았는데 self.thread 참조를 끊으면, 종료 루틴에서 참조할 메모리가 존재하지 않아잘못된 메모리 접근(0xC0000409)으로 앱이 강제 종료됨을 확인하였다.
해결: AlivePortWorker 객체를 리스트에 담아 참조를 유지
문제 2: 스레드 내부 OS blocking 후 종료 시점 충돌
시나리오
- AlivePortWorker가 포트 연결을 시도하며 내부적으로 blocking 상태
- 메인 스레드에서 timeout 발생 → quit() 호출 후 참조 해제
- blocking이 끝나고 종료 루틴에서 이미 해제된 메모리 접근
- 프로그램 강제 종료
해결 방안
- 모든 QThread 객체는 완전히 종료된 후 참조 해제
- quit() 호출 후 wait()로 명시적 종료 대기
- QThreadPool 또는 QFutureWatcher 등의 안전한 스레드 관리 방식 검토
개선된 구조 다이어그램

정리 및 결론
- PySide 환경에서는 블로킹 I/O에 주의
- 타이머 기반 제어는 블로킹 작업과 별도 스레드에서 분리해야 효과적
- QThread는 반드시 명시적으로 종료 및 메모리 해제 처리 필요
- 스레드 종료 전 참조 해제 금지 — 메모리 오류 위험
'날것 그대로의 공부기록 > 날 것 그대로 일지' 카테고리의 다른 글
| 컨트롤러만 테스트하기 (2) | 2025.08.04 |
|---|---|
| 동시성 환경에서 낙관적 락 + 재시도 전략 테스트 (참치캔 등록) (4) | 2025.08.04 |
| github action 자동배포 (3) | 2025.08.04 |
| 23년 6월 18일 생각들 (0) | 2023.06.18 |