ระบบปฏิบัติการเบื้องต้น
สวัสดีฮับ! ฉันอยากจะนำเสนอชุดบทความแปลของวรรณกรรมเรื่องหนึ่งที่น่าสนใจในความคิดเห็นของฉัน - OSTEP เนื้อหานี้จะตรวจสอบการทำงานของระบบปฏิบัติการที่มีลักษณะคล้ายยูนิกซ์อย่างลึกซึ้ง กล่าวคือ การทำงานกับกระบวนการ ตัวกำหนดเวลาต่างๆ หน่วยความจำ และส่วนประกอบอื่น ๆ ที่คล้ายกันซึ่งประกอบเป็นระบบปฏิบัติการสมัยใหม่ คุณสามารถดูต้นฉบับของวัสดุทั้งหมดได้ที่นี่
งานห้องปฏิบัติการในเรื่องนี้สามารถพบได้ที่นี่:
ส่วนอื่น ๆ :
คุณสามารถตรวจสอบช่องของฉันได้ที่
เตือน! มีแล็บสำหรับการบรรยายครั้งนี้! ดู
ประมวลผล API
ลองดูตัวอย่างการสร้างกระบวนการในระบบ UNIX มันเกิดขึ้นผ่านการเรียกสองระบบ ส้อม() и ผู้บริหาร ().
โทรส้อม()
พิจารณาโปรแกรมที่ทำการ fork() โทร ผลลัพธ์ของการดำเนินการจะเป็นดังนี้
ก่อนอื่น เราเข้าสู่ฟังก์ชัน main() และพิมพ์สตริงไปที่หน้าจอ บรรทัดนี้มีตัวระบุกระบวนการซึ่งในต้นฉบับเรียกว่า PID หรือตัวระบุกระบวนการ ตัวระบุนี้ใช้ใน UNIX เพื่ออ้างถึงกระบวนการ คำสั่งต่อไปจะเรียก fork() ณ จุดนี้ จะมีการสร้างสำเนาของกระบวนการที่เกือบจะทุกประการ สำหรับระบบปฏิบัติการ ดูเหมือนว่ามีโปรแกรมเดียวกันที่ทำงานบนระบบอยู่ 2 ชุด ซึ่งจะออกจากฟังก์ชัน fork() กระบวนการย่อยที่สร้างขึ้นใหม่ (ที่เกี่ยวข้องกับกระบวนการหลักที่สร้างขึ้น) จะไม่ถูกดำเนินการอีกต่อไป โดยเริ่มจากฟังก์ชัน main() ควรจำไว้ว่ากระบวนการย่อยไม่ใช่สำเนาที่แน่นอนของกระบวนการหลัก โดยเฉพาะอย่างยิ่ง มีพื้นที่ที่อยู่ของตัวเอง รีจิสเตอร์ของตัวเอง ตัวชี้ไปยังคำสั่งปฏิบัติการ และอื่นๆ ที่คล้ายคลึงกัน ดังนั้นค่าที่ส่งคืนไปยังผู้เรียกของฟังก์ชัน fork() จะแตกต่างกัน โดยเฉพาะอย่างยิ่ง กระบวนการหลักจะได้รับค่า PID ของกระบวนการย่อยเป็นการส่งคืน และรายการย่อยจะได้รับค่าเท่ากับ 0 เมื่อใช้โค้ดส่งคืนเหล่านี้ คุณสามารถแยกกระบวนการและบังคับให้แต่ละกระบวนการทำงานของตัวเองได้ . อย่างไรก็ตาม การทำงานของโปรแกรมนี้ไม่ได้กำหนดไว้อย่างเคร่งครัด หลังจากแบ่งออกเป็น 2 กระบวนการแล้ว OS จะเริ่มตรวจสอบและวางแผนงาน หากดำเนินการบนโปรเซสเซอร์แบบคอร์เดียว หนึ่งในกระบวนการ (ในกรณีนี้คือพาเรนต์) จะทำงานต่อไป จากนั้นกระบวนการย่อยจะได้รับการควบคุม เมื่อรีสตาร์ท สถานการณ์อาจแตกต่างกัน
รอสาย()
พิจารณาโปรแกรมต่อไปนี้ ในโปรแกรมนี้เนื่องจากการมีอยู่ของการโทร รอ() กระบวนการหลักจะรอให้กระบวนการย่อยเสร็จสิ้นเสมอ ในกรณีนี้ เราจะได้ผลลัพธ์ข้อความที่กำหนดไว้อย่างเคร่งครัดบนหน้าจอ
เรียก exec()
พิจารณาความท้าทาย ผู้บริหาร (). การเรียกของระบบนี้มีประโยชน์เมื่อเราต้องการรันโปรแกรมที่แตกต่างไปจากเดิมอย่างสิ้นเชิง ที่นี่เราจะโทร ผู้บริหารระดับสูง() เพื่อรันโปรแกรม wc ซึ่งเป็นโปรแกรมนับจำนวนคำ จะเกิดอะไรขึ้นเมื่อมีการเรียก exec()? การเรียกนี้ถูกส่งผ่านชื่อของไฟล์ปฏิบัติการและพารามิเตอร์บางตัวเป็นอาร์กิวเมนต์ หลังจากนั้นโค้ดและข้อมูลคงที่จากไฟล์ปฏิบัติการนี้จะถูกโหลดและเซ็กเมนต์ของตัวเองที่มีโค้ดจะถูกเขียนทับ พื้นที่หน่วยความจำที่เหลือ เช่น สแต็กและฮีป จะถูกเตรียมใช้งานใหม่ หลังจากนั้นระบบปฏิบัติการก็จะรันโปรแกรมโดยส่งชุดอาร์กิวเมนต์ไปให้มัน ดังนั้นเราจึงไม่ได้สร้างกระบวนการใหม่ เราเพียงแค่เปลี่ยนโปรแกรมที่กำลังทำงานอยู่ให้เป็นโปรแกรมอื่นที่กำลังทำงานอยู่ หลังจากดำเนินการเรียก exec() ในลูกหลานแล้ว ดูเหมือนว่าโปรแกรมดั้งเดิมไม่ได้ทำงานเลย
อาการแทรกซ้อนในการเริ่มต้นระบบนี้ถือเป็นเรื่องปกติสำหรับเชลล์ Unix และอนุญาตให้เชลล์นั้นรันโค้ดได้หลังจากการเรียก ส้อม()แต่ก่อนจะรับสาย ผู้บริหาร (). ตัวอย่างของโค้ดดังกล่าวคือการปรับสภาพแวดล้อมของเชลล์ให้ตรงกับความต้องการของโปรแกรมที่กำลังเปิดตัวก่อนที่จะเปิดตัว
เปลือก - เพียงแค่โปรแกรมผู้ใช้ เธอแสดงบรรทัดคำเชิญให้คุณดูและรอให้คุณเขียนบางอย่างลงไป ในกรณีส่วนใหญ่ ถ้าคุณเขียนชื่อของโปรแกรมที่นั่น เชลล์จะค้นหาตำแหน่งของมัน เรียกใช้เมธอด fork() จากนั้นเรียก exec() บางประเภทเพื่อสร้างกระบวนการใหม่และรอให้เสร็จสิ้นโดยใช้ รอ () โทร เมื่อกระบวนการลูกออก เชลล์จะกลับมาจากการเรียก wait() และพิมพ์พรอมต์อีกครั้งและรอให้ป้อนคำสั่งถัดไป
การแยก fork() & exec() ช่วยให้เชลล์ทำสิ่งต่อไปนี้ได้ เช่น:
ไฟล์ wc > new_file.
ในตัวอย่างนี้ เอาต์พุตของโปรแกรม wc ถูกเปลี่ยนเส้นทางไปยังไฟล์ วิธีที่เชลล์บรรลุผลนี้ค่อนข้างง่าย - โดยการสร้างกระบวนการลูกก่อนที่จะเรียกใช้ ผู้บริหาร ()เชลล์จะปิดเอาต์พุตมาตรฐานและเปิดไฟล์ new_fileดังนั้นเอาต์พุตทั้งหมดจากโปรแกรมที่รันอยู่ต่อไป wc จะถูกเปลี่ยนเส้นทางไปยังไฟล์แทนหน้าจอ
ท่อยูนิกซ์ มีการใช้งานในลักษณะเดียวกัน โดยมีความแตกต่างคือใช้การเรียกไปป์ () ในกรณีนี้ สตรีมเอาท์พุตของกระบวนการจะเชื่อมต่อกับคิวไปป์ที่อยู่ในเคอร์เนล ซึ่งจะเชื่อมต่อสตรีมอินพุตของกระบวนการอื่นด้วย
ที่มา: will.com