ใน Linux จะเกิดอะไรขึ้นกับสถานะของกระบวนการเมื่อต้องอ่านบล็อกจากดิสก์ ถูกบล็อกหรือไม่? ถ้าเป็นเช่นนั้นกระบวนการอื่นถูกเลือกให้ดำเนินการอย่างไร
ใน Linux จะเกิดอะไรขึ้นกับสถานะของกระบวนการเมื่อต้องอ่านบล็อกจากดิสก์ ถูกบล็อกหรือไม่? ถ้าเป็นเช่นนั้นกระบวนการอื่นถูกเลือกให้ดำเนินการอย่างไร
คำตอบ:
ในขณะที่รอread()
หรือwrite()
ไป / กลับจาก file descriptor กระบวนการจะอยู่ในโหมดสลีปพิเศษซึ่งเรียกว่า "D" หรือ "Disk Sleep" นี่เป็นเรื่องพิเศษเนื่องจากกระบวนการนี้ไม่สามารถฆ่าหรือหยุดชะงักได้ในขณะที่อยู่ในสถานะดังกล่าว กระบวนการที่รอการส่งคืนจาก ioctl () ก็จะเข้าสู่โหมดสลีปด้วยเช่นกัน
ข้อยกเว้นคือเมื่อไฟล์ (เช่นเทอร์มินัลหรืออุปกรณ์อักขระอื่น ๆ ) ถูกเปิดในO_NONBLOCK
โหมดส่งผ่านเมื่อสันนิษฐานว่าอุปกรณ์ (เช่นโมเด็ม) จะต้องใช้เวลาในการเริ่มต้น อย่างไรก็ตามคุณระบุบล็อกอุปกรณ์ในคำถามของคุณ นอกจากนี้ฉันยังไม่เคยลองสิ่งioctl()
ที่มีแนวโน้มว่าจะปิดกั้นบน fd ที่เปิดในโหมดไม่ปิดกั้น (อย่างน้อยก็ไม่รู้)
วิธีการเลือกกระบวนการอื่นขึ้นอยู่กับตัวกำหนดตารางเวลาที่คุณใช้รวมถึงกระบวนการอื่น ๆ ที่อาจทำเพื่อแก้ไขน้ำหนักของพวกเขาภายในตัวกำหนดตารางเวลานั้น
โปรแกรมพื้นที่ผู้ใช้บางส่วนภายใต้สถานการณ์บางอย่างเป็นที่ทราบกันดีว่ายังคงอยู่ในสถานะนี้ตลอดไปจนกว่าจะรีบูต โดยทั่วไปแล้วสิ่งเหล่านี้จะถูกจัดอยู่ในกลุ่ม "ซอมบี้" ตัวอื่น ๆ แต่คำศัพท์นั้นจะไม่ถูกต้องเนื่องจากพวกมันยังไม่สิ้นอายุในทางเทคนิค
เมื่อกระบวนการต้องการดึงข้อมูลจากดิสก์กระบวนการจะหยุดทำงานบน CPU อย่างมีประสิทธิภาพเพื่อให้กระบวนการอื่น ๆ ทำงานเนื่องจากการดำเนินการอาจใช้เวลานานในการดำเนินการให้เสร็จสมบูรณ์ - อย่างน้อย 5ms เวลาในการค้นหาสำหรับดิสก์เป็นเรื่องปกติและ 5ms คือ 10 ล้าน วงจร CPU ชั่วนิรันดร์จากมุมมองของโปรแกรม!
จากจุดโปรแกรมเมอร์ของมุมมอง (ยังกล่าวอีกว่า "ใน userspace") นี้เรียกว่าสายระบบการปิดกั้น หากคุณเรียกwrite(2)
(ซึ่งเป็นตัวห่อ libc แบบบาง ๆ รอบ ๆ การเรียกระบบที่มีชื่อเดียวกัน) กระบวนการของคุณจะไม่หยุดอยู่ที่ขอบเขตนั้นอย่างแน่นอน มันยังคงดำเนินต่อไปในเคอร์เนลรันรหัสการเรียกระบบ เวลาส่วนใหญ่จะไปถึงไดรเวอร์คอนโทรลเลอร์ดิสก์เฉพาะ (ชื่อไฟล์→ระบบไฟล์ / VFS →อุปกรณ์บล็อก→ไดรเวอร์อุปกรณ์) ซึ่งคำสั่งในการดึงบล็อกบนดิสก์จะถูกส่งไปยังฮาร์ดแวร์ที่เหมาะสมซึ่งเป็น การทำงานที่รวดเร็วเกือบตลอดเวลา
จากนั้นกระบวนการจะอยู่ในสถานะสลีป (ในพื้นที่เคอร์เนลการบล็อกเรียกว่าการนอนหลับ - ไม่มีสิ่งใดถูก 'ปิดกั้น' จากมุมมองของเคอร์เนล) จะถูกปลุกเมื่อฮาร์ดแวร์ดึงข้อมูลที่เหมาะสมได้ในที่สุดจากนั้นกระบวนการจะถูกทำเครื่องหมายว่ารันได้และจะถูกกำหนดเวลา ในที่สุดตัวกำหนดตารางเวลาจะรันกระบวนการ
สุดท้ายใน userspace การเรียกระบบการบล็อกจะกลับมาพร้อมกับสถานะและข้อมูลที่เหมาะสมและขั้นตอนของโปรแกรมจะดำเนินต่อไป
เป็นไปได้ที่จะเรียกใช้การเรียกระบบ I / O ส่วนใหญ่ในโหมดไม่ปิดกั้น (ดูO_NONBLOCK
ในopen(2)
และfcntl(2)
) ในกรณีนี้ระบบจะส่งกลับทันทีและรายงานเฉพาะการส่งการทำงานของดิสก์ โปรแกรมเมอร์จะต้องตรวจสอบอย่างชัดเจนในภายหลังว่าการดำเนินการเสร็จสมบูรณ์สำเร็จหรือไม่และดึงผลลัพธ์ออกมา (เช่นด้วยselect(2)
) สิ่งนี้เรียกว่าการเขียนโปรแกรมแบบอะซิงโครนัสหรือตามเหตุการณ์
คำตอบส่วนใหญ่ที่กล่าวถึงสถานะ D (ซึ่งเรียกTASK_UNINTERRUPTIBLE
ในชื่อสถานะของ Linux) ไม่ถูกต้อง Dรัฐเป็นโหมดพิเศษที่การนอนหลับซึ่งจะถูกเรียกเฉพาะในเส้นทางเคอร์เนลรหัสพื้นที่เมื่อเส้นทางรหัสที่ไม่สามารถขัดจังหวะ (เพราะมันจะซับซ้อนเกินไปในการเขียนโปรแกรม) ด้วยความคาดหวังว่ามันจะปิดกั้นเฉพาะสำหรับมาก ระยะเวลาอันสั้น. ฉันเชื่อว่า "D state" ส่วนใหญ่มองไม่เห็นจริงๆ พวกมันมีอายุสั้นมากและไม่สามารถสังเกตได้จากเครื่องมือการสุ่มตัวอย่างเช่น 'top'
คุณสามารถพบกับกระบวนการที่ไม่สามารถทำได้ในสถานะ D ได้ในบางสถานการณ์ NFS มีชื่อเสียงในเรื่องนั้นและฉันเคยพบมาหลายครั้ง ฉันคิดว่ามีการปะทะกันทางความหมายระหว่างเส้นทางรหัส VFS ซึ่งถือว่าเข้าถึงดิสก์ในเครื่องเสมอและการตรวจจับข้อผิดพลาดอย่างรวดเร็ว (บน SATA การหมดเวลาของข้อผิดพลาดจะอยู่ที่ประมาณไม่กี่ 100 มิลลิวินาที) และ NFS ซึ่งดึงข้อมูลจากเครือข่ายซึ่ง มีความยืดหยุ่นมากขึ้นและมีการกู้คืนที่ช้า (การหมดเวลา TCP 300 วินาทีเป็นเรื่องปกติ) อ่านบทความนี้สำหรับโซลูชันที่ยอดเยี่ยมที่แนะนำใน Linux 2.6.25 พร้อมTASK_KILLABLE
สถานะ ก่อนยุคนี้มีการแฮ็กที่คุณสามารถส่งสัญญาณไปยังไคลเอนต์กระบวนการ NFS ได้โดยส่ง SIGKILL ไปยังเคอร์เนลเธรดrpciod
แต่อย่าลืมเคล็ดลับที่น่าเกลียดนั้น…
/proc/stat
?
กระบวนการที่ดำเนินการ I / O จะอยู่ในสถานะ D (โหมดสลีปที่ไม่ถูกขัดจังหวะ)ซึ่งจะปลดปล่อย CPU จนกว่าจะมีการขัดจังหวะฮาร์ดแวร์ซึ่งจะบอกให้ CPU กลับไปดำเนินการตามโปรแกรม ดูman ps
สถานะกระบวนการอื่น ๆ
ขึ้นอยู่กับเคอร์เนลของคุณมีตัวกำหนดตารางเวลากระบวนการซึ่งติดตามรันคิวของกระบวนการที่พร้อมที่จะดำเนินการ พร้อมกับอัลกอริทึมการตั้งเวลาจะบอกเคอร์เนลว่ากระบวนการใดที่จะกำหนดให้ CPU ตัวใด มีกระบวนการเคอร์เนลและกระบวนการผู้ใช้ที่ต้องพิจารณา แต่ละกระบวนการจะได้รับการจัดสรรไทม์สไลซ์ซึ่งเป็นช่วงเวลาของ CPU ที่อนุญาตให้ใช้ เมื่อกระบวนการใช้ส่วนเวลาทั้งหมดแล้วกระบวนการจะถูกทำเครื่องหมายว่าหมดอายุและมีลำดับความสำคัญต่ำกว่าในอัลกอริทึมการตั้งเวลา
ใน2.6 เคอร์เนลมีตัวกำหนดตารางเวลาความซับซ้อนของเวลา O (1)ดังนั้นไม่ว่าคุณจะทำงานกี่กระบวนการมันจะกำหนด CPU ในเวลาคงที่ แม้ว่าจะมีความซับซ้อนมากขึ้นเนื่องจาก 2.6 แนะนำใบจองและการจัดสรรภาระงาน CPU ไม่ใช่อัลกอริทึมที่ง่าย ไม่ว่าในกรณีใดก็มีประสิทธิภาพและซีพียูจะไม่อยู่ในขณะที่คุณรอ I / O
ตามที่ผู้อื่นอธิบายไว้แล้วกระบวนการในสถานะ "D" (การนอนหลับไม่ต่อเนื่อง) มีหน้าที่ในการหยุดทำงานของกระบวนการ ps สำหรับฉันมันเกิดขึ้นหลายครั้งกับ RedHat 6.x และโฮมไดเร็กทอรี NFS ที่ติดตั้งอัตโนมัติ
ในการแสดงรายการกระบวนการในสถานะ D คุณสามารถใช้คำสั่งต่อไปนี้:
cd /proc
for i in [0-9]*;do echo -n "$i :";cat $i/status |grep ^State;done|grep D
หากต้องการทราบไดเร็กทอรีปัจจุบันของกระบวนการและอาจเป็นดิสก์ NFS ที่ติดตั้งซึ่งมีปัญหาคุณสามารถใช้คำสั่งที่คล้ายกับตัวอย่างต่อไปนี้ (แทนที่ 31134 ด้วยหมายเลขกระบวนการนอนหลับ):
# ls -l /proc/31134/cwd
lrwxrwxrwx 1 pippo users 0 Aug 2 16:25 /proc/31134/cwd -> /auto/pippo
ฉันพบว่าการให้คำสั่ง umount ด้วยสวิตช์ -f (บังคับ) ไปยังระบบไฟล์ nfs ที่เมาท์ที่เกี่ยวข้องสามารถปลุกกระบวนการนอนหลับได้:
umount -f /auto/pippo
ระบบไฟล์ไม่ได้ยกเลิกการต่อเชื่อมเนื่องจากไม่ว่าง แต่กระบวนการที่เกี่ยวข้องได้ทำการปลุกและฉันสามารถแก้ไขปัญหาได้โดยไม่ต้องรีบูตเครื่อง
สมมติว่ากระบวนการของคุณเป็นเธรดเดียวและคุณกำลังใช้การบล็อก I / O กระบวนการของคุณจะบล็อกการรอให้ I / O เสร็จสมบูรณ์ เคอร์เนลจะเลือกกระบวนการอื่นเพื่อเรียกใช้ในระหว่างนี้โดยพิจารณาจากความสวยงามลำดับความสำคัญเวลารันล่าสุด ฯลฯ หากไม่มีกระบวนการอื่นที่รันได้เคอร์เนลจะไม่ทำงานใด ๆ แต่จะบอกฮาร์ดแวร์ว่าเครื่องไม่ได้ใช้งาน (ซึ่งจะส่งผลให้ใช้พลังงานน้อยลง)
กระบวนการที่กำลังรอให้ I / O เสร็จสมบูรณ์มักจะแสดงในสถานะ D ในเช่นps
และtop
.
ใช่งานถูกบล็อกในการเรียกระบบ read () งานอื่นที่พร้อมทำงานหรือถ้าไม่มีงานอื่นพร้อมงานที่ไม่ได้ใช้งาน (สำหรับ CPU นั้น) จะทำงาน
ปกติการปิดกั้นการอ่านแผ่นดิสก์จะทำให้งานเข้าสู่สถานะ "D" (ตามที่คนอื่น ๆ ระบุไว้) งานดังกล่าวนำไปสู่ค่าเฉลี่ยการโหลดแม้ว่าจะไม่ใช้ CPU ก็ตาม
IO อื่น ๆ บางประเภทโดยเฉพาะ ttys และเครือข่ายทำงานไม่เหมือนกัน - กระบวนการจะสิ้นสุดในสถานะ "S" และอาจถูกขัดจังหวะและไม่นับรวมกับค่าเฉลี่ยโหลด
โดยทั่วไปกระบวนการจะบล็อก หากการดำเนินการอ่านอยู่บนตัวอธิบายไฟล์ที่ทำเครื่องหมายว่าไม่ปิดกั้นหรือหากกระบวนการใช้ IO แบบอะซิงโครนัสจะไม่บล็อก นอกจากนี้หากกระบวนการมีเธรดอื่นที่ไม่ถูกบล็อกก็สามารถทำงานต่อไปได้
การตัดสินใจว่ากระบวนการใดจะรันต่อไปขึ้นอยู่กับตัวกำหนดตารางเวลาในเคอร์เนล