บทความนี้เป็นเรื่องเกี่ยวกับการใช้คลาส _thread กับไมโครคอนโทรลเลอร์ ESP32 ซึ่งมีหน่วยประมวลผล 2 แกน (core) แต่อย่างไรก็ดีคลาสเธรดเป็นโมดูลที่เป็นส่วนย่อยจากโมดูล cython และขณะที่เขียนบทความยังไม่สมบูรณ์พร้อมใช้งาน โดยโครงสร้างของคลาสเป็นดังภาพที่ 1 และคลาสย่อย LockType เป็นดังภาพที่ 2
_thread
คำสั่งสำหรับสร้างเธรดมีรูปแบบดังนี้
_thread.start_new_thread( โปรแกรม, (รายการพารามิเตอร์))
การสร้างเธรดจะต้องเขียนโปรแกรมย่อยเตรียมไว้โดยกำหนดรายการพารามิเตอร์ให้ตรงกับการเรียกในคำสั่ง _thread.start_new_thread( ) และการออกจากเธรดใช้คำสั่งดังนี้
_thread.exit( )
การอ่านค่า ID ของเธรดใช้รูปแบบดังนี้
หมายเลขของเธรด = _thread.get_ident()
การกำหนดขนาดของหน่วยความจำสแตกให้กับเธรด และอ่านค่าปริมาณหน่วยความจำสแตกของเธรดใช้คำสั่งดังนี้
_thread.stack_size( ขนาดที่ต้องการ )
ขนาดสแตก = _thread.stack_size()
ตัวอย่างการใช้ _thread เป็นดังโปรแกรม demoThread1
# demoThread1
import _thread
# demoThread1
import _thread
import time
import random
runningTimes = [random.randint(3,8), random.randint(2,5)]
def myFunc(delay, id):
global runningTimes
while (runningTimes[id] > 0):
time.sleep(delay)
print('Running thread No.{} with delay = {}.'.format(id, delay))
runningTimes[id] -= 1
print("Thread No.{} ... end game!".format(id))
_thread.exit()
if __name__=="__main__":
for i in range(2):
print("run thread No.{}, {} times.".format(i, runningTimes[i]))
_thread.start_new_thread(myFunc, (random.randint(1, 4), i))
print("End of main Program")
จากตัวอย่าง demoThread1 ที่เป็นการสร้างเธรดจำนวน 2 เธรดเพื่อทำงานเป็นฉากหลัง เมื่อเธรดถูกสร้างเสร็จโปรแกรมหลักเสร็จสิ้นการทำงานแต่เธรดทั้งสองยังคงทำงานต่อไป โดยแต่ละเธรดทำงานเป็นการหน่วงเวลาตามที่สุ่มให้ และเมื่อเธรดทำงานจนครบตามจำนวนครั้งที่สุ่มจะออกจากการวนรอบ while แล้วรายงานการจบการทำงานของเธรด และเรียก _thread.exit() ดังตัวอย่างในภาพที่ 3
ตัวอย่างการอ่านค่า ID ของเธรดหลักและของเธรดพร้อมแสดงจำนวนสแตกของแต่ละเธรดเป็นดัง demoThread2 และตัวอย่างผลลัพธ์ของการทำงานเป็นดังภาพที่ 4
# demoThread2
import _thread
def myFunc(id, msg):
print("ID : {}".format(_thread.get_ident()))
print("Stack size : {}".format(_thread.stack_size()))
print("Thread No.{} ... end game!\n".format(id))
_thread.exit()
if __name__=="__main__":
print("get_ident = {}".format(_thread.get_ident()))
for i in range(2):
print("run thread No.{}.".format(i))
_thread.start_new_thread(myFunc, (i, "Ho"))
print("End of main Program\n")
LockType
เป็นคลาสสำหรับสร้างสเตต (state) หรือสถานะการล็อกหรือยกเลิกการล็อกทรัพยากรที่อาจจะถูกเข้าถึงด้วยโพรเสสหลายตัวพร้อม ๆ กัน คำสั่งใช้งานของคลาสนี้ได้แก่
สถานะการถูกล็อก = Lock.locked()
Lock.acquire()
Lock.release()
ซึ่งจะพบว่ามีเพียง 3 คำสั่งสำหรับตรวจสอบสถานะ การขอล็อก และการยกเลิกการล็อกตามลำดับ ตัวอย่างโปรแกรมเป็นดังนี้
# demoThread3
import _thread
objLocked = _thread.allocate_lock()
def myFunc(id, msg):
global objLocked
while not objLocked.acquire():
print("{}w/".format(id))
if (objLocked.locked()):
objLocked.release()
print("Thread No.{} ... end game!\n".format(id))
_thread.exit()
if __name__=="__main__":
print("get_ident = {}".format(_thread.get_ident()))
for i in range(2):
print("run thread No.{}.".format(i))
_thread.start_new_thread(myFunc, (i, "Ho"))
print("End of main Program\n")
สรุป
เนื่องจากคลาส _thread ยังไม่สมบูรณ์ในขณะที่เขียนบทความ ประกอบกับ thonny ไม่รองรับการทำงานเบื้องหลังทำให้เกิดข้อผิดพลาดระหว่างทดสอบโปรแกรม อย่างไรก็ดี ทีมเราหวังว่าผู้อ่านคงได้เห็นภาพรวม และสามารถใช้การสร้างเธรดเพื่อให้มีการเรียกใช้งานโปรแกรมเบื้องหลังที่หลากหลายขึ้นนอกจากใช้การขัดจังหวะหรือการตั้งเวลา สุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ
ท่านใดต้องการพูดคุยสามารถคอมเมนท์ไว้ได้เลยครับ
แหล่งอ้างอิง
(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-07-21, 2021-10-27