[1] Thread (어제 수업 이어서)
https://powerstone829.tistory.com/82
[Day56] 2022-04-18(월) 라즈베리파이5 - Thread - 김서연 강사님
[1] Thread - threading 모듈을 이용해서 작업 1. 파이썬에서 threading 모듈을 사용하는 방법1 - Thread 클래스 객체 생성 1) 멀티쓰레드로 즉, 독립적인 실행흐름을 갖고 실행하고 싶은 코드를 함수로 정의
powerstone829.tistory.com
1. Thread 클래스 상속 이용 예제
1) 예제1
# threading_inheritance_exam1.py
# Thread 클래스 상속받아서 클래스 작성
# A : 65, Z : 90
# - 두 개의 클래스를 만들어서 쓰레드를 생성한다.
# - AlphaThread 클래스
# - printAlpha메소드를 정의하고, A......Z까지 출력
# - DigitThread 클래스
# - printDigit 메소드를 정의하고, 1....30까지 출력
from threading import Thread
import time
class AlphaThread(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
for i in range(65, 91):
print(chr(i))
time.sleep(0.5)
class DigitThread(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
for i in range(1, 31):
print('\t', i)
time.sleep(0.5)
if __name__ == "__main__":
alpha = AlphaThread()
digit = DigitThread()
print("Main Thread Start")
alpha.daemon = True # 이렇게 세팅하면 메인쓰레드 종료하면 생성된 쓰레드도 같이 종료
digit.daemon = True
alpha.start()
digit.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("Main Thread End")
※ crtl + c 입력하면 메인 쓰레드는 종료되지만, 생성된 쓰레드는 종료되지 않는 문제 해결
- Thread객체.daemon = True
- 메인 쓰레드가 종료되면 생성된 쓰레드가 자동으로 종료
- while문 등으로 메인 쓰레드가 계속 돌 수 있도록 해줘야 한다.
https://stackoverflow.com/questions/11815947/cannot-kill-python-script-with-ctrl-c
Cannot kill Python script with Ctrl-C
I am testing Python threading with the following script: import threading class FirstThread (threading.Thread): def run (self): while True: print 'first' class SecondThre...
stackoverflow.com
2) 예제2
# threading_inheritance_test2.py
from threading import Thread
import requests
import time
class Html(Thread):
def __init__(self, url):
Thread.__init__(self)
self.url = url
def run(self):
response = requests.get(self.url)
time.sleep(1)
print(self.url, len(response.text), response.text)
print("test.......")
# getHtml 함수를 멀티쓰레드로 실행되도록 처리
t1 = Html('https://www.naver.com')
t1.start() # 쓰레드를 생성해서 적절한 시점에 호출(스케줄러에 의해)
time.sleep(1.2)
print("프로그램 종료+++++++++++++++++++++++")
3) 예제3
# threading_led_inheritance_exam.py
# - Main Thread : "Main Thread"를 1초에 한 번씩 출력하는 주 쓰레드
# - Thread 클래스 : 1초에 LED의 전구가 on/off가 반복되도록 쓰레드 작성하기(함수명 : blink_led)
import RPi.GPIO as gpio
from threading import Thread
import time
led_pin = 22
gpio.setmode(gpio.BCM)
gpio.setup(led_pin, gpio.OUT)
class Led(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
print("blink_led 시작")
try:
while True:
gpio.output(led_pin, gpio.HIGH)
time.sleep(0.5)
gpio.output(led_pin, gpio.LOW)
time.sleep(0.5)
except RuntimeError:
pass
finally:
print("blink_led 종료")
ledThread = Led()
ledThread.start()
print("Main Thread 시작")
try:
while True:
print("main쓰레드")
time.sleep(1)
except KeyboardInterrupt:
pass
finally:
gpio.cleanup()
print("Main Thread 종료")
2. 동기화
- 멀티 쓰레드 프로그래밍을 할 때 쓰레드들이 공유자원에 동시에 접근하는 경우 무결하지 못한 데이터가 발생
- 공유 자원 : 모든 쓰레드가 사용하는 객체
- 무결하지 못한 데이터 : 신뢰할 수 없는 데이터
- 임계영역(Critical section) : 공유 데이터 접근해서 사용하는 코드
- 문제 해결을 위한 방법 중 상호배제 사용
- 두 개 이상의 쓰레드가 임계영역에 진입하지 못하도록 하는 것
-> Lock 객체를 이용해서 상호 배제를 처리
-> 한 쓰레드가 공유객체를 점유해서 사용하는 동안 공유객체에 lock을 걸어서 접근하지 못하도록 처리
- 적용 방법
① 공유객체 내부에서 Lock 객체를 생성
② 공유해서 사용하는 부분의 전에 Lock객체의 acquire( )를 호출
- 한 쓰레드만 소유하고 다른 쓰레드는 대기 상태에 있을 수 있도록 작업
③ 소유해서 사용하던 Lock을 해제 : release( )
- 대기 상태에 있는 쓰레드가 공유객체를 점유하고 lock객체를 획득
1) 동기화가 되지 않는 경우 예제
# toilet.py
import threading
# 모든 객체가 공유해서 사용하는 객체
class Toilet:
def __init__(self):
pass
# 공유해서 사용할 기능이 정의된 메소드
def open(self, name):
print(name+"이 문열고 들어옴")
for i in range(100000000):
if i == 10000:
print(name+"이 끙~~~~~~~~아~~~~~~~~")
print(name+"이 문열고 나감")
# user.py
import string
from threading import Thread
class User(Thread):
def __init__(self, name:string, toilet:object): # toilet 객체는 사용자 쓰레드가 공유해서 사용할 객체
super().__init__()
self.name = name
self.toilet = toilet
def run(self): # 쓰레드로 실행되어지는 run메소드에서 공유객체를 사용
self.toilet.open(self.name)
# toilet_test.py
from toilet import Toilet
from user import User
print("작업 시작")
# 공유객체 만들기
toilet = Toilet()
# 쓰레드 객체를 7개 생성해서 작업해보기
User("RM", toilet).start()
User("제이홉", toilet).start()
User("슈가", toilet).start()
User("진", toilet).start()
User("뷔", toilet).start()
User("정국", toilet).start()
User("지민", toilet).start()
2) 동기화 사용 예제
- 위의 코드에서 toilet.py 만 수정해주면 된다.
# toilet.py
from threading import Lock
# 모든 객체가 공유해서 사용하는 객체
class Toilet:
def __init__(self):
self.lock = Lock()
# 공유해서 사용할 기능이 정의된 메소드
def open(self, name):
# Lock객체의acquire메소드를 호출하면 Lock객체를 사용하는 쓰레드가 점유(쓰레드가 점유해서 Toilet객체의 open메소드를 사용하는 동안 다른 쓰레드는 호출하지 못하고 대기 상테에 있을 수 있도록 설정)
self.lock.acquire()
print(name+"이 문열고 들어옴")
for i in range(1000000):
if i == 10000:
print(name+"이 끙~~~~~~~~아~~~~~~~~")
print(name+"이 문열고 나감")
self.lock.release() # 한 쓰레드에서 작업이 끝나면 lock을 해제
[2] Web 에서 MQTT와 웹소켓 활용
- front 페이지에서 web과 broker의 통신은 sub/pub가 지속되어야 한다.
-> 즉, 실시간으로 subscribe/publish할 수 있어야 한다.
- 이러한 작업은 websocket 통신을 이용해서 작업해야 한다.
- 본래 websocket 통신을 구현하려면 복잡한 코드 작성이 필요하다.
- 하지만, mosquitto(broker)가 websocket 통신을 지원한다.
-> 따라서, back-end에서 websocket통신을 위한 코드를 직접 작성하지 않아도 된다.
1. Django 환경 세팅
https://powerstone829.tistory.com/26?category=1006501
[Day18] 2022-02-21(월) Web Application 1 - Django 환경 셋팅 - 이진만 강사님
[1] Web Application Settings 1. Web Server 2. Python Projcet - Web application 추가 - django Server 3. 개발 순서 1) Python Project 생성 2) 서드파트 모듈 설치 pip 버전 최신버전으로 업그레이드 dja..
powerstone829.tistory.com
2. 웹소켓 통신 설정
1) mosquitto의 설정 파일을 변경
- 기본 설정은 일반적인 MQTT 통신만 지원되도록 설정된 상태
- 일반적인 MQTT통신과 websocket 통신이 모두 지원되도록 변경 필요(포트가 두 개 열려 있어야 함)
① mosquitto.conf 파일에 내용 추가
- 경로> C:\Program Files\mosquitto
- mosquitto.conf 파일을 관리자 권한으로 열어서, 맨 밑에 다음 내용을 추가
listener 9001
protocol websockets
#mqtt
listener 1883
protocol mqtt
② 명령 프롬프트에서 broker 실행
- C:\Program Files\mosquitto 로 경로 변경하고 실행(mosquitto.conf 파일 때문)
명령어> mosquitto -c mosquitto.conf -v
2) websocket 통신을 할 html 페이지에 MQTT JavaScript CDN 추가
<script src = "https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js"
type = "text/javascript"> </script>
https://www.eclipse.org/paho/index.php?page=clients/js/index.php
Eclipse Paho | The Eclipse Foundation
The Eclipse Foundation - home to a global community, the Eclipse IDE, Jakarta EE and over 415 open source projects, including runtimes, tools and frameworks.
www.eclipse.org
3) publish 를 위한 함수들 정의
<script type="text/javascript">
var host = "172.30.1.57";
var port = 9001;
var mqtt;
// callback 함수 - 접속이 완료된 후 호출되는 함수
function onConnect(){
console.log("접속완료");
}
// callback 함수 - 접속이 실패된 후 호출되는 함수
function onFailure(){
console.log("접속실패");
}
// publish하는 함수 정의
function sendMsg(msg){
// alert(msg);
/*
1. message 객체 생성
2. topic 설정
3. send 메소드를 호출
*/
message = new Paho.MQTT.Message(msg);
message.destinationName = "iot/led"; // 토픽 설정
// MQTT 메시지 보내기 - publish
mqtt.send(message);
}
// mqtt통신을 관리하기 위한 사용자 정의 함수
function MQTTConnect(){
console.log("mqtt접속:"+host+","+port)
// mqtt 통신을 위한 클라이언트 객체 생성
mqtt = new Paho.MQTT.Client(host, port, "javascript_client"); // "javascript_client" 클라이언트 ID
// mqtt 통신을 위해 필요한 설정을 명시
var options = {
timeout: 3,
onSuccess: onConnect, // 접속 성공 시 실행되는 callback함수 등록
onFailure: onFailure,
}
mqtt.connect(options);
}
</script>
4) body 태그 내 코드 - mqtt 접속을 위한 함수 호출
<body>
<script type="text/javascript">
// 사용자 정의 함수를 호출해서 mqtt가 동작할 수 있도록 해준다.
MQTTConnect()
</script>
<h1>MQTT와 웹소켓 테스트</h1>
<div id="data"></div>
<form>
<input type="button" value="led켜기" onclick="sendMsg('led_on')">
<input type="button" value="led끄기" onclick="sendMsg('led_off')">
</form>
</body>
5) 라즈베리파이에서 subscribe
- message 받아서 LED on/off 작동하는 코드
# led_Subscriber.py
# 라즈베리파이 subscriber
# message -> led_on : led켜기
# message -> led_off : led끄기
import paho.mqtt.client as client
import RPi.GPIO as gpio
led_pin = 22
gpio.setmode(gpio.BCM)
gpio.setup(led_pin, gpio.OUT)
def connect_result(client, userdata, flags, rc):
print("connect...", rc)
if rc == 0:
client.subscribe("iot/led")
else:
print("연결실패")
def on_message(client, userdata, msg):
message = msg.payload.decode("utf-8")
print(message)
if message == "led_on":
gpio.output(led_pin, gpio.HIGH)
elif message == "led_off":
gpio.output(led_pin, gpio.LOW)
try:
mqttClient = client.Client()
mqttClient.on_connect = connect_result
mqttClient.on_message = on_message
mqttClient.connect("XXX.XXX.XXX.XXX", 1883, 60)
mqttClient.loop_forever()
except KeyboardInterrupt():
pass
finally:
gpio.cleanup()
6) 웹페이지 접속하여 led_on, led_off 버튼 클릭하여, LED on/off 작동하는지 확인
- 끝 -
'프로젝트형 IoT 서비스 개발 4회차 > 3. 게이트웨이 디바이스 제어' 카테고리의 다른 글
[Day59] 2022-04-21(목) 라즈베리파이8 - 온습도 센서(DHT11) - 김서연 강사님 (0) | 2022.04.21 |
---|---|
[Day58] 2022-04-20(수) 라즈베리파이7 - WebSocket2, 외부접속허용, 센서(초음파, PIR) - 김서연 강사님 (0) | 2022.04.20 |
[Day56] 2022-04-18(월) 라즈베리파이5 - Thread1 - 김서연 강사님 (1) | 2022.04.18 |
[Day55] 2022-04-15(금) 라즈베리파이4 - MQTT2(paho.mqtt) - 김서연 강사님 (0) | 2022.04.15 |
[Day54] 2022-04-14(목) 라즈베리파이3 - MQTT1 - 김서연 강사님 (2) | 2022.04.14 |