คลาสเธรดใน Delphi
Raptor[สตูดิโอจิต]
http://mental.mentu.com
ที่สาม
หลังจากพูดถึง Constructor แล้ว เรามาดู Destructor กันดีกว่า:
ตัวทำลาย TThread.Destroy;
เริ่ม
ถ้า (FThreadID <> 0) และไม่ได้ FFinished แล้ว
เริ่ม
ยุติ;
ถ้า FCreateSuspended แล้ว
ประวัติย่อ;
รอก่อน;
จบ;
ถ้า FHandle <> 0 แล้ว CloseHandle(FHandle);
สืบทอดมาทำลาย;
FFatalException ฟรี;
ลบเธรด;
จบ;
ก่อนที่เธรดอ็อบเจ็กต์จะถูกปล่อยออกมา ให้ตรวจสอบก่อนว่าเธรดยังคงดำเนินการอยู่หรือไม่ หากเธรดยังคงดำเนินการอยู่ (รหัสเธรดไม่ใช่ 0 และไม่ได้ตั้งค่าแฟล็กสิ้นสุดเธรด) กระบวนการยุติจะถูกเรียกเพื่อสิ้นสุดเธรด กระบวนการยุติเพียงตั้งค่าสถานะสิ้นสุดของคลาสเธรด ดังในรหัสต่อไปนี้:
ขั้นตอน TThread.Terminate;
เริ่ม
FTerminated := จริง;
จบ;
ดังนั้น เธรดจะต้องยังคงดำเนินการต่อไปจนกว่าจะสิ้นสุดตามปกติ แทนที่จะยุติเธรดทันที ซึ่งควรสังเกตไว้
พูดนอกเรื่องเล็กน้อยที่นี่: หลายคนถามฉันถึงวิธีการยุติเธรด "ทันที" (แน่นอนหมายถึงเธรดที่สร้างด้วย TThread) แน่นอนว่ามันไม่ได้ผล! วิธีเดียวที่จะยุติเธรดคือปล่อยให้วิธี Execute ดำเนินการจนเสร็จสิ้น ดังนั้น โดยทั่วไปแล้ว หากคุณต้องการให้เธรดของคุณยุติโดยเร็วที่สุด คุณจะต้องตรวจสอบแฟล็ก Terminated ในวิธี Execute อย่างต่อเนื่องภายในระยะเวลาอันสั้น ดังนั้น ที่คุณสามารถออกได้ทันเวลา นี่เป็นหลักการที่สำคัญมากเมื่อออกแบบโค้ดแบบเธรด!
แน่นอน หากคุณต้องออกจากเธรด "ทันที" ได้ คลาส TThread ก็ไม่ใช่ตัวเลือกที่ดี เพราะหากคุณใช้ API เพื่อบังคับยุติเธรด อ็อบเจ็กต์เธรด TThread จะไม่ถูกปล่อยออกมาอย่างถูกต้องในที่สุด และ การละเมิดการเข้าถึงจะเกิดขึ้นเมื่อวัตถุถูกทำลาย ในกรณีนี้ คุณสามารถใช้ได้เฉพาะฟังก์ชัน API หรือ RTL เพื่อสร้างเธรดเท่านั้น
หากเธรดอยู่ในสถานะถูกระงับการเริ่มต้น ให้โอนเธรดไปยังสถานะกำลังทำงาน จากนั้นเรียก WaitFor เพื่อรอ ฟังก์ชันคือการรอจนกว่าเธรดจะสิ้นสุดก่อนที่จะดำเนินการต่อไป การใช้งาน WaitFor จะมีการอธิบายในภายหลัง
หลังจากที่เธรดสิ้นสุด ปิดหมายเลขอ้างอิงของเธรด (หมายเลขอ้างอิงมีอยู่ภายใต้การสร้างเธรดปกติ) และปล่อยวัตถุเธรดที่สร้างโดยระบบปฏิบัติการ
จากนั้นเรียกTObject.Destroyเพื่อปล่อยวัตถุนี้ และปล่อยวัตถุข้อยกเว้นที่ตรวจพบ และสุดท้ายเรียกRemoveThreadเพื่อลดจำนวนเธรดในกระบวนการ
ลักษณะอื่น ๆ ที่เกี่ยวข้องกับการตั้งค่า Suspend/Resume และลำดับความสำคัญของเธรดจะไม่ใช่จุดเน้นของบทความนี้ และจะไม่ถูกกล่าวถึงอีก สิ่งที่จะกล่าวถึงด้านล่างนี้คืออีกสองประเด็นสำคัญของบทความนี้: Synchronize และ WaitFor
แต่ก่อนที่จะแนะนำฟังก์ชันทั้งสองนี้ จำเป็นต้องแนะนำเทคโนโลยีการซิงโครไนซ์เธรดอื่น ๆ อีกสองรายการ: เหตุการณ์และส่วนสำคัญ
กิจกรรมแตกต่างจากกิจกรรมใน Delphi โดยพื้นฐานแล้ว Event เทียบเท่ากับตัวแปรบูลีนโกลบอล มีการดำเนินการมอบหมายสองแบบ: ตั้งค่าและรีเซ็ต ซึ่งเทียบเท่ากับการตั้งค่าเป็นจริงหรือเท็จ และการตรวจสอบค่านั้นทำได้ผ่านการดำเนินการ WaitFor ตามแพลตฟอร์ม Windows มีฟังก์ชัน API สามแบบ: SetEvent, ResetEvent และ WaitForSingleObject (มี API หลายตัวที่ใช้ฟังก์ชัน WaitFor ซึ่งเป็นฟังก์ชันที่ง่ายที่สุด)
ทั้งสามนี้เป็นแบบพื้นฐาน ดังนั้น Event จึงสามารถนำแอปพลิเคชันไปใช้ในหลายเธรดซึ่งตัวแปรบูลีนทั่วไปไม่สามารถทำได้ มีการกล่าวถึงฟังก์ชั่นของ Set และ Reset ไปแล้ว ตอนนี้เรามาพูดถึงฟังก์ชั่นของ WaitFor กันดีกว่า:
หน้าที่ของ WaitFor คือการตรวจสอบว่าสถานะของ Event เป็นสถานะ Set หรือไม่ (เทียบเท่ากับ True) หากไม่เป็นเช่นนั้นจะรอให้เปลี่ยนเป็นสถานะ Set ทันที เธรดที่เรียก WaitFor อยู่ในสถานะถูกระงับ นอกจากนี้ WaitFor ยังมีพารามิเตอร์สำหรับการตั้งค่าการหมดเวลา หากพารามิเตอร์นี้เป็น 0 จะไม่รอและส่งคืนสถานะเหตุการณ์ทันที หากเป็นค่า INFINITE จะรอไม่สิ้นสุดจนกว่าสถานะ Set จะเกิดขึ้น รอตามจำนวนมิลลิวินาทีที่สอดคล้องกัน จากนั้นจึงคืนสถานะของเหตุการณ์
เมื่อเหตุการณ์เปลี่ยนจากสถานะรีเซ็ตเป็นสถานะตั้งค่า จะทำให้เธรดอื่นๆ ถูกระงับเนื่องจากเหตุการณ์ WaitFor ด้วยเหตุนี้จึงเรียกว่าเหตุการณ์ สิ่งที่เรียกว่า "เหตุการณ์" หมายถึง "การเปลี่ยนแปลงของรัฐ" ข้อมูล "การเปลี่ยนสถานะ" นี้สามารถส่งผ่านระหว่างเธรดผ่านกิจกรรมได้
แน่นอนว่า ฟังก์ชั่นที่คล้ายกันนี้สามารถทำได้โดยใช้ตัวแปรบูลีนที่มีการป้องกัน (ดูการแนะนำส่วนสำคัญด้านล่าง) ตราบใดที่ WaitFor จะถูกแทนที่ด้วยโค้ดวนซ้ำที่ตรวจสอบค่าบูลีน ในทางปฏิบัติแล้วไม่มีปัญหาเลย แต่ในการใช้งานจริงคุณจะพบว่าการรอดังกล่าวจะใช้ทรัพยากร CPU จำนวนมาก ลดประสิทธิภาพของระบบ และส่งผลต่อความเร็วในการประมวลผลของเธรดอื่น ๆ ดังนั้นจึงไม่ประหยัดและบางครั้งก็เป็นไปได้ด้วยซ้ำ จะมี ปัญหา. ดังนั้นจึงไม่แนะนำให้ใช้วิธีนี้
(จะดำเนินต่อไป)