ความแตกต่างระหว่าง fork () และ vfork () คืออะไร


13

ฉันต้องการที่จะเข้าใจในรายละเอียดความแตกต่างระหว่าง fork () และ vfork () ฉันไม่สามารถแยกแยะหน้าคนได้อย่างสมบูรณ์

ฉันต้องการชี้แจงเพื่อนร่วมงานคนหนึ่งให้ความเห็นว่า " ใน Linux ปัจจุบันไม่มี vfork () แม้ว่าคุณจะเรียกมันว่ามันจะเรียกส้อมภายใน () "

คำตอบ:


24

หน้าคนมักจะเป็นเอกสารอ้างอิงสั้น ๆ วิกิพีเดียเป็นสถานที่ที่ดีกว่าสำหรับการอธิบายแนวคิด

ทำซ้ำกระบวนการ: สร้างกระบวนการลูกซึ่งเกือบจะเหมือนกับกระบวนการหลัก (ความแตกต่างที่ชัดเจนที่สุดคือกระบวนการใหม่มีรหัสกระบวนการที่แตกต่างกัน) โดยเฉพาะอย่างยิ่ง fork (conceptually) ต้องคัดลอกหน่วยความจำของกระบวนการพาเรนต์ทั้งหมด

เนื่องจากค่อนข้างแพง vfork ถูกคิดค้นเพื่อจัดการกรณีพิเศษทั่วไปที่ไม่จำเป็นต้องทำสำเนา บ่อยครั้งสิ่งแรกที่กระบวนการลูกทำคือการโหลดอิมเมจโปรแกรมใหม่ดังนั้นนี่คือสิ่งที่เกิดขึ้น:

if (fork()) {
    # parent process …
} else {
    # child process (with a new copy of the process memory)
    execve("/bin/sh", …);  # discard the process memory
}

การexecveเรียกจะโหลดโปรแกรมที่เรียกใช้งานได้ใหม่และสิ่งนี้จะแทนที่รหัสของกระบวนการและหน่วยความจำข้อมูลด้วยรหัสของโปรแกรมที่เรียกใช้งานใหม่และหน่วยความจำข้อมูลใหม่ ดังนั้นสำเนาหน่วยความจำทั้งหมดที่สร้างโดยforkทั้งหมดเพื่ออะไร

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

if (vfork()) {
    # parent process
    cmd = NULL; # modify the only copy of cmd
} else {
    # child process
    execve("/bin/sh", "sh", "-c", cmd, (char*)NULL);  # read the only copy of cmd
}

ตั้งแต่การประดิษฐ์ vfork การเพิ่มประสิทธิภาพที่ดีขึ้นได้ถูกประดิษฐ์ขึ้น ระบบที่ทันสมัยส่วนใหญ่รวมถึง Linux ใช้รูปแบบcopy-on-writeโดยที่หน้าในหน่วยความจำกระบวนการจะไม่ถูกคัดลอกในเวลาที่ทำการforkโทร แต่ต่อมาเมื่อผู้ปกครองหรือลูกเขียนลงในหน้าแรก กล่าวคือแต่ละหน้าเริ่มต้นด้วยการแชร์และยังคงแชร์จนกว่ากระบวนการใดกระบวนการหนึ่งจะเขียนไปยังหน้านั้น กระบวนการที่เขียนได้รับหน้าทางกายภาพใหม่ (ด้วยที่อยู่เสมือนเดียวกัน) การคัดลอกเมื่อเขียนทำให้ vfork ส่วนใหญ่ไม่มีประโยชน์เนื่องจากforkจะไม่ทำสำเนาใด ๆ ในกรณีที่vforkสามารถใช้งานได้

Linux เก็บ vfork ไว้ การforkเรียกระบบจะต้องทำสำเนาของตารางหน่วยความจำเสมือนของกระบวนการแม้ว่าจะไม่ได้คัดลอกหน่วยความจำจริง vforkไม่จำเป็นต้องทำเช่นนี้ด้วยซ้ำ การปรับปรุงประสิทธิภาพนั้นไม่มีความสำคัญในแอปพลิเคชันส่วนใหญ่


1
ขอบคุณสำหรับคำตอบที่ยอดเยี่ยมนี้ .. ขณะทำ fork () เด็ก ๆ จะได้รับ ID กระบวนการใหม่และพื้นที่เสมือนที่เกี่ยวข้องแล้วทำไมมันยังควรทำสำเนาของตารางหน่วยความจำเสมือนของกระบวนการ ฉันไม่ชัดเจนในส่วนนั้น
Sen

@Sen: forkจำเป็นต้องสร้างการแมปหน่วยความจำเสมือนแยกต่างหากเพื่อให้สำเนาที่คัดลอกเมื่อเขียนมีผลต่อหนึ่งในสองกระบวนการเท่านั้น
Gilles 'หยุดความชั่วร้าย'

คุณแน่ใจหรือไม่ว่ากระบวนการหลักกำลังทำงานอยู่
qbolec

2

fork()และvfork()syscalls จะแตกต่างกัน

fork()syscall สร้างกระบวนการที่สองเหมือนกันกับหน่วยความจำที่แยกต่างหาก vfork()syscall สร้างกระบวนการที่สองที่ใช้หน่วยความจำเดียวกัน

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

สำหรับข้อมูลเพิ่มเติมคลิกที่นี่

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