สถานะกระบวนการของ Linux


90

ใน Linux จะเกิดอะไรขึ้นกับสถานะของกระบวนการเมื่อต้องอ่านบล็อกจากดิสก์ ถูกบล็อกหรือไม่? ถ้าเป็นเช่นนั้นกระบวนการอื่นถูกเลือกให้ดำเนินการอย่างไร

คำตอบ:


88

ในขณะที่รอread()หรือwrite()ไป / กลับจาก file descriptor กระบวนการจะอยู่ในโหมดสลีปพิเศษซึ่งเรียกว่า "D" หรือ "Disk Sleep" นี่เป็นเรื่องพิเศษเนื่องจากกระบวนการนี้ไม่สามารถฆ่าหรือหยุดชะงักได้ในขณะที่อยู่ในสถานะดังกล่าว กระบวนการที่รอการส่งคืนจาก ioctl () ก็จะเข้าสู่โหมดสลีปด้วยเช่นกัน

ข้อยกเว้นคือเมื่อไฟล์ (เช่นเทอร์มินัลหรืออุปกรณ์อักขระอื่น ๆ ) ถูกเปิดในO_NONBLOCKโหมดส่งผ่านเมื่อสันนิษฐานว่าอุปกรณ์ (เช่นโมเด็ม) จะต้องใช้เวลาในการเริ่มต้น อย่างไรก็ตามคุณระบุบล็อกอุปกรณ์ในคำถามของคุณ นอกจากนี้ฉันยังไม่เคยลองสิ่งioctl()ที่มีแนวโน้มว่าจะปิดกั้นบน fd ที่เปิดในโหมดไม่ปิดกั้น (อย่างน้อยก็ไม่รู้)

วิธีการเลือกกระบวนการอื่นขึ้นอยู่กับตัวกำหนดตารางเวลาที่คุณใช้รวมถึงกระบวนการอื่น ๆ ที่อาจทำเพื่อแก้ไขน้ำหนักของพวกเขาภายในตัวกำหนดตารางเวลานั้น

โปรแกรมพื้นที่ผู้ใช้บางส่วนภายใต้สถานการณ์บางอย่างเป็นที่ทราบกันดีว่ายังคงอยู่ในสถานะนี้ตลอดไปจนกว่าจะรีบูต โดยทั่วไปแล้วสิ่งเหล่านี้จะถูกจัดอยู่ในกลุ่ม "ซอมบี้" ตัวอื่น ๆ แต่คำศัพท์นั้นจะไม่ถูกต้องเนื่องจากพวกมันยังไม่สิ้นอายุในทางเทคนิค


1
"กระบวนการที่รอการส่งคืนจาก ioctl () ก็จะเข้าสู่โหมดสลีปในลักษณะนี้เช่นกัน" ฉันเพิ่งฆ่ากระบวนการ userspace ของฉันที่รอ IOCTL บล็อกดังนั้นนี่จึงไม่เป็นความจริง เว้นแต่ฉันจะเข้าใจผิด
Hamzahfrq

คงเป็นเรื่องยากมากที่จะต้องใช้เวลาทดสอบเช่นนี้ ไม่สามารถฆ่ากระบวนการที่ไม่หยุดชะงักได้ หากคุณสามารถฆ่ามันได้มันก็แค่ปิดกั้น (เคอร์เนลไม่ได้อยู่ตรงกลางส่วนใด ๆ ของ ioctl และคัดลอกการตอบสนองที่เกี่ยวข้องกับพื้นที่ผู้ใช้ในตำแหน่งที่คุณผ่าน (หรืออย่างน้อยก็ไม่ได้อยู่ใน กลางของการคัดลอก)) ลินุกซ์ได้เปลี่ยนแปลงไปมากเช่นกันตั้งแต่ปี 2009 เมื่อสิ่งนี้ถูกเขียนขึ้น ปรากฏการณ์นี้สังเกตได้น้อยกว่าที่เคยเป็นมา
Tim Post

133

เมื่อกระบวนการต้องการดึงข้อมูลจากดิสก์กระบวนการจะหยุดทำงานบน 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แต่อย่าลืมเคล็ดลับที่น่าเกลียดนั้น…


2
+1 สำหรับคำตอบโดยละเอียด แต่โปรดทราบว่าชุดข้อความนี้มีคำตอบที่ยอมรับมาเกือบสองปีแล้ว คลิกลิงก์ "คำถาม" หากคุณต้องการให้ความช่วยเหลือเกี่ยวกับคำถามล่าสุด ยินดีต้อนรับสู่ Stack Overflow และขอขอบคุณที่ร่วมให้ข้อมูล!
GargantuChet

20
คำตอบนี้เป็นคำตอบเดียวที่จะกล่าวถึง NFS ซึ่งในบางสภาพแวดล้อมเป็นคำอธิบายที่พบบ่อยที่สุดสำหรับกระบวนการในสถานะ D +1.
Pinko

14
คำตอบที่ดีมากขอบคุณ นอกจากนี้โปรดทราบว่ากระบวนการจะเข้าสู่สถานะ D ในขณะที่รอเพจที่ถูกสลับออกดังนั้นกระบวนการเค้นจะอยู่ในสถานะ D เป็นเวลานาน
cha0site

@zerodeux คำตอบที่ดี แต่ฉันคิดว่าสคีมาของคุณ (ชื่อไฟล์ -> ระบบไฟล์ / VFS -> บล็อกอุปกรณ์ -> ไดรเวอร์อุปกรณ์) ควรเป็น (ชื่อไฟล์ -> VFS -> ระบบไฟล์ (ext3) -> บล็อกอุปกรณ์ -> ไดรเวอร์อุปกรณ์)
c4f4t0r

1
มันจะปลอดภัยที่จะคิดว่าเวลาที่ใช้ในการรอคอยเคอร์เนลใน spinlocks (ซึ่งอาจจะหรืออาจจะไม่ได้เกี่ยวข้องกับดิสก์ I / O) ทั้งหมดรายงานว่า D-ของรัฐใน/proc/stat?
wick

8

กระบวนการที่ดำเนินการ I / O จะอยู่ในสถานะ D (โหมดสลีปที่ไม่ถูกขัดจังหวะ)ซึ่งจะปลดปล่อย CPU จนกว่าจะมีการขัดจังหวะฮาร์ดแวร์ซึ่งจะบอกให้ CPU กลับไปดำเนินการตามโปรแกรม ดูman psสถานะกระบวนการอื่น ๆ

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

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


3

ตามที่ผู้อื่นอธิบายไว้แล้วกระบวนการในสถานะ "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

ระบบไฟล์ไม่ได้ยกเลิกการต่อเชื่อมเนื่องจากไม่ว่าง แต่กระบวนการที่เกี่ยวข้องได้ทำการปลุกและฉันสามารถแก้ไขปัญหาได้โดยไม่ต้องรีบูตเครื่อง


1

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

กระบวนการที่กำลังรอให้ I / O เสร็จสมบูรณ์มักจะแสดงในสถานะ D ในเช่นpsและtop.


ฉันเปิดตัวหลายกระบวนการโดยใช้ประมาณ 10% ของหน่วยความจำทั้งหมด ฉันสังเกตว่าหลายคนอยู่ในสถานะ D นี่เป็นเพราะ IO ที่ช้าในเครื่องนี้หรือไม่? สมมติว่าฉันมี 9 กระบวนการพวกเขาอาจจะแข่งขันกันเพื่อ IO และส่วนใหญ่อยู่ในสถานะ D
Kemin Zhou

@KeminZhou เมื่อเทียบกับความเร็วของ CPU แล้ว I / O ค่อนข้างช้า - แม้แต่ I / O ที่เร็ว กระบวนการ I / O ที่หนักหน่วงเพียงครั้งเดียวอาจทำให้ดิสก์แม่เหล็กยุ่งได้ง่ายแม้กระทั่ง SSD 10 กระบวนการหนักของ I / O อาจยุ่งอยู่บ้าง
derobert

1

ใช่งานถูกบล็อกในการเรียกระบบ read () งานอื่นที่พร้อมทำงานหรือถ้าไม่มีงานอื่นพร้อมงานที่ไม่ได้ใช้งาน (สำหรับ CPU นั้น) จะทำงาน

ปกติการปิดกั้นการอ่านแผ่นดิสก์จะทำให้งานเข้าสู่สถานะ "D" (ตามที่คนอื่น ๆ ระบุไว้) งานดังกล่าวนำไปสู่ค่าเฉลี่ยการโหลดแม้ว่าจะไม่ใช้ CPU ก็ตาม

IO อื่น ๆ บางประเภทโดยเฉพาะ ttys และเครือข่ายทำงานไม่เหมือนกัน - กระบวนการจะสิ้นสุดในสถานะ "S" และอาจถูกขัดจังหวะและไม่นับรวมกับค่าเฉลี่ยโหลด


0

ใช่งานที่รอ IO ถูกบล็อกและงานอื่น ๆ จะถูกดำเนินการ เลือกงานต่อไปจะกระทำโดยการจัดตารางเวลาลินุกซ์


0

โดยทั่วไปกระบวนการจะบล็อก หากการดำเนินการอ่านอยู่บนตัวอธิบายไฟล์ที่ทำเครื่องหมายว่าไม่ปิดกั้นหรือหากกระบวนการใช้ IO แบบอะซิงโครนัสจะไม่บล็อก นอกจากนี้หากกระบวนการมีเธรดอื่นที่ไม่ถูกบล็อกก็สามารถทำงานต่อไปได้

การตัดสินใจว่ากระบวนการใดจะรันต่อไปขึ้นอยู่กับตัวกำหนดตารางเวลาในเคอร์เนล

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.