ทำไมลูกของ vfork หรือ fork call _exit () แทนที่จะออก ()


12

จากหน้าคนของvfork():

vfork () แตกต่างจาก fork () ซึ่งผู้ปกครองจะถูกระงับจนกว่าเด็กจะเรียกร้องให้ execve (2) หรือ _exit (2) ชายด์แบ่งใช้หน่วยความจำทั้งหมดกับพาเรนต์รวมถึงสแต็กจนกว่า execve () จะออกโดยเด็ก เด็กต้องไม่ส่งคืนจากฟังก์ชันปัจจุบันหรือ call exit () แต่อาจเรียก _exit ()

ทำไมเด็กควรใช้_exit()มากกว่าเพียงแค่การเรียกร้องexit()? ฉันหวังว่านี้สามารถใช้ได้กับทั้งสองและvfork()fork()


2
หากคุณสนใจในการสนทนา
xenoterracide

คำตอบ:


11

ในฐานะที่เห็นก่อนหน้านี้ , vforkไม่อนุญาตให้กระบวนการเด็กในการเข้าถึงหน่วยความจำของผู้ปกครอง exitเป็นฟังก์ชั่นไลบรารี C (นั่นคือสาเหตุที่มักจะเขียนเป็นexit(3)) จะดำเนินการล้างข้อมูลงานต่างๆเช่นการล้างและปิดลำธาร C (ไฟล์ที่เปิดผ่านฟังก์ชั่นประกาศในstdio.h) atexitและการดำเนินงานฟังก์ชั่นที่ผู้ใช้กำหนดลงทะเบียนกับ งานทั้งหมดนี้เกี่ยวข้องกับการอ่านและการเขียนหน่วยความจำกระบวนการ

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

หลังจากforkนั้นไม่มีข้อ จำกัด ดังกล่าวกระบวนการพ่อแม่และลูกตอนนี้เป็นอิสระอย่างสมบูรณ์


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

หลังจาก fork ไม่มีข้อ จำกัด ดังกล่าวกระบวนการพ่อแม่และลูกตอนนี้เป็นอิสระอย่างสมบูรณ์ หมายความว่าฉันสามารถเรียกexit ()จากลูกของ fork หรือไม่?
Sen

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

@Sen: หลังจากทางแยกคุณสามารถโทรออกหรือฟังก์ชั่นอื่น ๆ ทุกกระบวนการเริ่มต้นหลังจาก fork (บน Linux แม้กระบวนการเริ่มต้นinitจะถูกแยกโดยเคอร์เนล)
Gilles 'หยุดความชั่วร้าย'

3

exitทำความสะอาดเพิ่มเติมเช่นฟังก์ชั่นการโทรที่ลงทะเบียนโดยatexitเข้าถึงข้อมูลนอกส่วนที่คัดลอก _exitดำเนินการ syscall โดยตรงโดยไม่ต้องล้างข้อมูลใด ๆ ยกเว้นในเคอร์เนล


... และควรสังเกตว่า fork () ทำสำเนาทุกอย่างดังนั้นคุณจึงสามารถเรียกใช้ exit () และคุณสามารถกลับจากฟังก์ชันปัจจุบันได้อย่างแน่นอน
Derobert

3

คุณมีลูกที่เรียก _exit () เพื่อหลีกเลี่ยงการล้างข้อมูล stdio (หรืออื่น ๆ ) บัฟเฟอร์เมื่อกระบวนการลูกออก เนื่องจากกระบวนการลูกถือเป็นสำเนาที่แน่นอนของกระบวนการหลักกระบวนการลูกยังคงมีสิ่งที่ผู้ปกครองมีใน "stdout" หรือ "stderr" บัฟเฟอร์จาก <stdio.h> คุณสามารถ (และจะในเวลาที่ไม่เหมาะสม) รับเอาท์พุทสองครั้งโดยการเรียก exit () หนึ่งตัวจาก atexit handler ของโพรเซสลูกและอีกอันจากพาเรนต์เมื่อบัฟเฟอร์ในกระบวนการพาเรนต์เต็มและรับฟลัช

ฉันตระหนักถึงคำตอบข้างต้นมุ่งเน้นไปที่ stdio.h เฉพาะ แต่ความคิดนั้นอาจนำไปสู่ ​​I / O บัฟเฟอร์อื่น ๆ เช่นเดียวกับหนึ่งในคำตอบข้างต้นบ่งบอกถึง


1

exit(): - ดำเนินการล้างข้อมูลบางอย่างเช่นปิดสตรีม i / o และอื่น ๆ จากนั้นกลับสู่เคอร์เนล _exit(): - มาที่เคอร์เนลโดยตรง (อย่าดำเนินการล้างข้อมูลใด ๆ )

fork() : ทั้งผู้ปกครองและเด็กมีตารางไฟล์ที่แตกต่างกันดังนั้นการเปลี่ยนแปลงที่ทำโดยเด็กจะไม่ส่งผลต่อพารามิเตอร์สภาพแวดล้อมของผู้ปกครองและในทางกลับกัน

vfork(): ทั้ง parent และ child ใช้ตารางไฟล์เดียวกันดังนั้นการเปลี่ยนแปลงที่ทำโดย child จะมีผลกับพารามิเตอร์ของ parent เช่นตัวแปรบางตัวvar=10เรียกใช้var++โดยเด็กแล้วเรียกใช้ parent คุณสามารถเห็นผลกระทบของvar++ผลลัพธ์ใน parent ได้เช่นกัน

ที่ผมกล่าวว่าถ้าคุณใช้exit()ในvfork()แล้วทั้งหมด I / O จะปิดอยู่แล้ว ดังนั้นแม้ว่าผู้ปกครองจะทำงานอย่างถูกต้องคุณไม่สามารถรับเอาท์พุทที่เหมาะสมได้เนื่องจากตัวแปรทั้งหมดจะถูกลบทิ้งและกระแสข้อมูลทั้งหมดจะถูกปิด

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