행복한 하루
Raspberry Pi에서 쓰레드(Thread)와 메시지 큐(Message Queue) 통신 이용해 보기(Python) 본문
Raspberry Pi에서 쓰레드(Thread)와 메시지 큐(Message Queue) 통신 이용해 보기(Python)
변화의 물결 2022. 5. 22. 17:05
안녕하세요.
라즈베리 파이 프로그램에서 쓰레드를 2개 이상 사용할 경우 쓰레드 간에 데이터를 주고받아야 하는 경우가 있습니다. 혹은 인터럽트 처리를 중 값을 전달해야 할 경우도 있습니다.
단순한 장난감 자동차를 예를 들어 개발한 한다고 했을 경우, 핸들 조작을 감지하는 쓰레드와, 앞뒤를 감지하는 센서 인터럽트 쓰레드가 필요하고, 이 조작에 따라 모터가 동작하는 쓰레드가 필요하다고 가정합니다.
이럴 경우 쓰레드 간에 메시지를 주고받아야 하는 경우에 메시지 큐를 통해 주고받을 수 있습니다.
대략적은 그림으로 표현하자면 다음과 같습니다.
1. 소스 확인
- Queue, Thread 호출에 필요한 라이브러리를 import 합니다.
- Queue 크기를 설정해서 메모리에 초기화합니다.
- Queue에 데이터를 넣는 Thread 2개(handle, sensor)와 Queue에서 값을 출력하는 Thread 1개(Motor)로 구현합니다.
import queue
import threading
import time
flag_exit = False
QUEUE_SIZE = 10
mq = queue.Queue(QUEUE_SIZE)
def handle_main() :
while True:
#print("\tHandle")
mq.put("Handle");
time.sleep(0.5)
global flag_exit
if (flag_exit):
break
def sensor_main() :
while True :
#print("\tSensor")
mq.put("Sensor");
time.sleep(1)
global flag_exit
if (flag_exit) :
break
def motor_main() :
while True :
try :
data = mq.get(True,2)
print("Data " + data)
global flag_exit
if (flag_exit) :
break
except queue.Empty:
print("Stop")
break
def main():
print("Thread & Message Queue Example")
try:
t1 = threading.Thread(target=handle_main)
t1.start()
t2 = threading.Thread(target=sensor_main)
t2.start()
t3 = threading.Thread(target=motor_main)
t3.start()
while True:
time.sleep(0.1)
except KeyboardInterrupt:
print("Ctrl+C Pressed.")
global flag_exit
flag_exit = True
t1.join()
t2.join()
t3.join()
if __name__ == "__main__":
main()
- Queue와 Thread 동시에 사용하다 보니, Ctrl+C 사용해서 종료할 때 에러 메시지들이 나왔습니다. 그래서 조금 편법으로 에러를 나오지 않게 구현해보았습니다. 정확한 구현이 아니므로 필요하다면 Python에 대해 이해 후 수정해서 사용해야 할 것으로 보입니다.
- Thread에서 변수를 공유하기 위해서 global 예약어 사용해서 flag_exit 선언했습니다. (추가로, 여기서는 읽기만 하기 때문에 Lock을 사용하지 않았지만, 변수에 쓰기(Write)를 한다면 Lock을 걸어주어야 합니다. lock.acquire(), lock.release()를 검색해서 찾아보시면 됩니다.)
- queue.get() 경우 기본값이 block=True 이므로 queue 안에 값이 없으면 대기상태가 됩니다. 그래서 중간에 중단하려면 멈춘 것처럼 대기 상태가 됩니다. 이 상황을 막기 위해서 몇 가지 방법이 있지만, 그중에 선택한 것은, block 상태에서 값이 없으면 2초 후에 빠져나오게 하였습니다.
- queue 값이 없는 상태에서 중간에 빠져나오면이 없다고 에러가 발생했는데 그것을 처리하기 위해서 except queue.Empty로 예외 처리를 하였습니다.
2. 실행 결과
- 조작하는 Thread와 출력하는 Thread가 Queue를 공유하며 동작하는 하는 것을 확인할 수 있습니다.
- 위의 Python 코드는 완벽하게 마무리된 것이 아니기 때문에 다른 에러 상황도 발생할 수 있으니, 참고하여 보완해야 할 수 있습니다.
감사합니다.
<참고사이트>
1. 동기화된 큐 클래스
https://docs.python.org/ko/3.7/library/queue.html
2. 파이썬(Python) Thread – 동기화 설명
https://niceman.tistory.com/139
3. Why can I not catch a Queue.Empty exception from a multiprocessing Queue?
'RaspberryPi' 카테고리의 다른 글
Quest3-Pico W - 클라우드 연결 및 데이터 업로드(화재감지기) (0) | 2022.09.22 |
---|---|
[도서 실습] Qt 5 and OpenCV 4 Computer Vision (Raspberry Pi CM 4 – ImageEditor) (0) | 2022.06.18 |
Raspberry Pi Zero 2 W 외부 안테나(External Antenna) 장착하기 (0) | 2022.03.21 |
라즈베리 파이 4(Raspberry Pi 4) 2.9" TOUCH E-PAPER HAT 테스트 (0) | 2022.03.13 |
라즈베리파이(Raspberry Pi 4)에 RTSP 서버 설치하기 (에러 발생 부분들 확인) (0) | 2022.01.28 |