กลับไปหน้าบทความ

อ่าน 3 นาที

ยุ่งอยู่กับการรอคอย

ในวิทยาการคอมพิวเตอร์และวิศวกรรมซอฟต์แวร์ การรอคอยแบบยุ่ง ( busy-waiting) การวนซ้ำ แบบยุ่ง ( busy-looping)หรือการหมุนวน (spinning)เป็นเทคนิคที่กระบวนการตรวจสอบเงื่อนไขซ้ำๆ เช่น...

ยุ่งอยู่กับการรอคอย

ในวิทยาการคอมพิวเตอร์และวิศวกรรมซอฟต์แวร์ การรอคอยแบบยุ่ง ( busy-waiting) การวนซ้ำ แบบยุ่ง ( busy-looping)หรือการหมุนวน (spinning)เป็นเทคนิคที่กระบวนการตรวจสอบเงื่อนไขซ้ำๆ เช่น การป้อนข้อมูล จากแป้นพิมพ์หรือการล็อกพร้อมใช้งานหรือไม่ การหมุนวนยังสามารถใช้เพื่อสร้างความล่าช้าตามเวลาที่กำหนด ซึ่งเป็นเทคนิคที่จำเป็นในระบบที่ไม่มีวิธีการรอเป็นระยะเวลาที่กำหนด ความเร็วของโปรเซสเซอร์แตกต่างกันอย่างมากในแต่ละคอมพิวเตอร์ โดยเฉพาะอย่างยิ่งโปรเซสเซอร์บางตัวได้รับการออกแบบให้ปรับความเร็วแบบไดนามิกตามภาระงานปัจจุบัน[ 1 ]ดังนั้น การหมุนวนในฐานะเทคนิคการหน่วงเวลาสามารถสร้างผลลัพธ์ที่ไม่สอดคล้องกันหรือคาดเดาไม่ได้ในระบบต่างๆ เว้นแต่จะมีโค้ดเพื่อกำหนดเวลาที่โปรเซสเซอร์ใช้ในการดำเนินการลูป "ไม่ทำอะไรเลย" หรือโค้ดการวนซ้ำจะตรวจสอบนาฬิกาแบบเรียลไทม์อย่าง ชัดเจน

ในกรณีส่วนใหญ่ การหมุนถือเป็นรูปแบบที่ไม่พึงประสงค์และควรหลีกเลี่ยง[ 2 ]เนื่องจากเวลาประมวลผลที่สามารถใช้ในการดำเนินการงาน อื่น กลับถูกใช้ไปกับกิจกรรมที่ไร้ประโยชน์ การหมุนอาจเป็นกลยุทธ์ที่ถูกต้องในบางสถานการณ์ โดยเฉพาะอย่างยิ่งในการใช้งานspinlocksภายในระบบปฏิบัติการที่ออกแบบมาเพื่อทำงานบนระบบSMP

ตัวอย่าง

ตัวอย่างโค้ด Javaต่อไปนี้แสดงให้เห็นถึงสองเธรดที่ใช้ตัวแปรจำนวนเต็มi ส่วนกลางร่วมกัน เธรดแรกใช้การรอแบบวนซ้ำ (busy-waiting) เพื่อตรวจสอบการเปลี่ยนแปลงของค่าตัวแปรi:

แพ็คเกจorg.wikipedia.examples ;import java.util.concurrent.atomic.AtomicInteger ;public class Example { // จำนวนเต็มอะตอมิกที่ใช้ร่วมกันระหว่างเธรดstatic AtomicInteger i = new AtomicInteger ( 0 );public static void main ( String [] args ) throws InterruptedException { // เธรด f1: รอให้ i เปลี่ยนจาก 0 เธรดt1 = new Thread (() -> { int local ; while (( local = i . get ()) == 0 ) { // Busy-wait (spinlock) } System . out . printf ( "ค่าของ i เปลี่ยนเป็น %d.%n" , local ); });// เธรด f2: เปลี่ยนค่า i หลังจาก 10 วินาทีเธรดt2 = เธรดใหม่(() -> { int local = 99 ; try { Thread . sleep ( 10_000 ); // พัก 10 วินาที} catch ( InterruptedException e ) { Thread . currentThread (). interrupt (); return ; } i . set ( local ); System . out . printf ( "t2 ได้เปลี่ยนค่าของ i เป็น %d.%n" , local ); });// เริ่มเธรดt1.start ( ); t2.start ( );// รอให้เธรดทำงานเสร็จt1.join ( ) ; t2.join ( );System.out.println ( " All threads finished. " ) ; } }

ในกรณีการใช้งานแบบนี้ เราอาจพิจารณาใช้ตัวแปรเงื่อนไขด้วยเช่นกัน

ทางเลือกอื่นๆ

ระบบปฏิบัติการและไลบรารีการทำงานแบบมัลติเธรดส่วนใหญ่มี คำสั่งระบบ (system call)หลากหลายรูปแบบที่สามารถบล็อกกระบวนการเมื่อเกิดเหตุการณ์บางอย่าง เช่น การได้มาซึ่งล็อก การเปลี่ยนแปลงของตัวจับเวลา ความ พร้อมใช้งานของ I/Oหรือสัญญาณต่างๆการใช้คำสั่งเหล่านี้โดยทั่วไปจะให้ผลลัพธ์ที่ง่ายที่สุด มีประสิทธิภาพที่สุด ยุติธรรมที่สุด และ ปราศจากปัญหาการแย่งชิง ทรัพยากร (race condition) คำสั่งเดียวจะตรวจสอบ แจ้งตัวจัดตารางเวลาเกี่ยวกับเหตุการณ์ที่กำลังรออยู่ แทรกตัวกั้นหน่วยความจำ (memory barrier)ในกรณีที่เหมาะสม และอาจดำเนินการ I/O ตามที่ร้องขอ ก่อนที่จะส่งคืนค่า กระบวนการอื่นๆ สามารถใช้ CPU ได้ในขณะที่ผู้เรียกถูกบล็อก ตัวจัดตารางเวลาจะได้รับข้อมูลที่จำเป็นในการใช้การสืบทอดลำดับความสำคัญหรือกลไกอื่นๆ เพื่อหลีกเลี่ยงการอดอยาก

การรอคอยอย่างไม่หยุดยั้งนั้นสามารถลดความสิ้นเปลืองลงได้มากโดยใช้ฟังก์ชันหน่วงเวลา (เช่น `delay` sleep()) ซึ่งพบได้ในระบบปฏิบัติการส่วนใหญ่ ฟังก์ชันนี้จะทำให้เธรดหยุดทำงานชั่วคราวเป็นเวลาที่กำหนด ซึ่งในระหว่างนั้นเธรดจะไม่เสียเวลาของ CPU เลย หากลูปตรวจสอบสิ่งง่ายๆ เธรดก็จะใช้เวลาส่วนใหญ่ในการหยุดทำงานชั่วคราวและจะเสียเวลาของ CPU น้อยมาก

หากต้องการระยะเวลาหน่วงสั้นๆ มักจะมีฟังก์ชันที่ช่วยให้ส่งต่อการควบคุมไปยังโปรเซสเซอร์อื่นๆ ได้โดยไม่ต้องรอเวลาใดๆ

ในโปรแกรมที่ไม่สิ้นสุด (เช่น ระบบปฏิบัติการ) การรอแบบไม่สิ้นสุดสามารถทำได้โดยใช้การกระโดดแบบไม่มีเงื่อนไข ดังแสดงใน ไวยากรณ์ NASM นี้ :

jmp $

CPU จะกระโดดไปยังตำแหน่งของตัวเอง โดยไม่มีเงื่อนไข ตลอดไป การรอแบบวนลูปเช่นนี้สามารถแทนที่ด้วย:

นอนหลับ: hlt jmp sleep

สำหรับข้อมูลเพิ่มเติม โปรดดูHLT (คำสั่ง x86 )

การใช้งานที่เหมาะสม

ในการเขียนโปรแกรมระดับต่ำ การรอแบบวนลูปอาจเป็นสิ่งที่พึงประสงค์ การประมวลผลแบบใช้การขัดจังหวะอาจไม่เหมาะสมหรือทำได้จริงสำหรับอุปกรณ์ฮาร์ดแวร์ทุกตัว โดยเฉพาะอย่างยิ่งอุปกรณ์ที่ใช้งานไม่บ่อย บางครั้งจำเป็นต้องเขียนข้อมูลควบคุมบางอย่างลงในฮาร์ดแวร์ แล้วดึงสถานะของอุปกรณ์ที่ได้จากการเขียนข้อมูลนั้น ซึ่งสถานะดังกล่าวอาจไม่ถูกต้องจนกว่าจะผ่านไปหลายรอบการทำงานของเครื่องหลังจากเขียนข้อมูลแล้ว โปรแกรมเมอร์อาจเรียกใช้ฟังก์ชันหน่วงเวลาของระบบปฏิบัติการ แต่การทำเช่นนั้นอาจใช้เวลานานกว่าการรอให้อุปกรณ์ส่งสถานะกลับมาเพียงไม่กี่รอบการทำงานของนาฬิกา

ดูเพิ่มเติม

  • คำอธิบายจากเอกสารข้อกำหนดพื้นฐานของ The Open Group ฉบับที่ 6, IEEE Std 1003.1, ฉบับปี 2004
  • บทความ " การล็อกแบบหมุนระดับผู้ใช้ - เธรด กระบวนการ และ IPC " โดยGert Boddaert
  • เอกสารอ้างอิงคลาส SpinLock ของออสเตรียถูกเก็บถาวรเมื่อวันที่ 14 พฤษภาคม 2011 ที่Wayback Machine
ดึงข้อมูลมาจาก " https://en.wikipedia.org/w/index.php?title=Busy_waiting&oldid=1356435325 "

สรุปเนื้อหา

ข้อมูลสำคัญจากบทความ

ข้อมูลสำคัญเกี่ยวกับ ยุ่งอยู่กับการรอคอย

ในวิทยาการคอมพิวเตอร์และวิศวกรรมซอฟต์แวร์ การรอคอยแบบยุ่ง ( busy-waiting) การวนซ้ำ แบบยุ่ง ( busy-looping)หรือการหมุนวน (spinning)เป็นเทคนิคที่กระบวนการตรวจสอบเงื่อนไขซ้ำๆ เช่น...

ตัวอย่าง

ตัวอย่างโค้ด Java ต่อไปนี้แสดงให้เห็นถึงสองเธรดที่ใช้ ตัวแปรจำนวนเต็ม i ส่วนกลางร่วมกัน เธรดแรกใช้การรอแบบวนซ้ำ (busy-waiting) เพื่อตรวจสอบการเปลี่ยนแปลงของค่าตัวแปร i :

ทางเลือกอื่นๆ

ระบบปฏิบัติการและไลบรารีการทำงานแบบมัลติเธรดส่วนใหญ่มี คำสั่งระบบ (system call) หลากหลายรูปแบบที่สามารถ บล็อก กระบวนการเมื่อเกิดเหตุการณ์บางอย่าง เช่น การได้มาซึ่งล็อก การเปลี่ยนแปลงของตัวจับเวลา ความ พร้อมใช้งานของ I/O หรือ สัญญาณต่างๆ...

การใช้งานที่เหมาะสม

ในการเขียนโปรแกรมระดับต่ำ การรอแบบวนลูปอาจเป็นสิ่งที่พึงประสงค์ การประมวลผลแบบใช้การขัดจังหวะอาจไม่เหมาะสมหรือทำได้จริงสำหรับอุปกรณ์ฮาร์ดแวร์ทุกตัว โดยเฉพาะอย่างยิ่งอุปกรณ์ที่ใช้งานไม่บ่อย บางครั้งจำเป็นต้องเขียนข้อมูลควบคุมบางอย่างลงในฮาร์ดแวร์...