ทำไมส้อมกลไกการสร้างกระบวนการเริ่มต้นคืออะไร?


46

การเรียกใช้ระบบ UNIX สำหรับการสร้างกระบวนการ fork () สร้างกระบวนการลูกโดยการคัดลอกกระบวนการหลัก ความเข้าใจของฉันคือสิ่งนี้มักจะตามมาด้วยการเรียกร้องให้ exec () เพื่อแทนที่พื้นที่หน่วยความจำของกระบวนการลูก (รวมถึงส่วนของข้อความ) การคัดลอกพื้นที่หน่วยความจำของผู้ปกครองในทางแยก () ดูเหมือนจะสิ้นเปลืองกับฉันเสมอ (แม้ว่าฉันจะรู้ว่าของเสียสามารถลดลงได้ด้วยการทำให้ส่วนหน่วยความจำคัดลอกตามการเขียนดังนั้นจึงคัดลอกเฉพาะพอยน์เตอร์เท่านั้น) มีใครรู้บ้างไหมว่าทำไมจึงต้องใช้วิธีการทำสำเนานี้สำหรับการสร้างกระบวนการ


3
โปรดทราบว่าfork(2)หน้า man ภายใต้ Linux บอกว่า: Under Linux, fork() is implemented using copy-on-write pages, so the only penalty that it incurs is the time and memory required to duplicate the parent's page tables, and to create a unique task structure for the child. ฉันจินตนาการ (แต่ไม่ทราบแน่ชัด) ว่านี่เป็นกรณีของ Unix รสชาติสมัยใหม่อื่น ๆ
ลาร์สก์

4
PDP-11 Unix ตัวจริงทำสำเนาไบต์ทั้งหมดของกระบวนการแยก: แต่มันมี 64Kb ที่ปฏิบัติการได้และที่ 64Kb ส่วนใหญ่ของข้อมูลดังนั้นมันจึงไม่เป็นภาระมากแม้แต่ในปี 1975 ฉันจะ เดาว่าทุกๆ unix และ unix-a-like ตั้งแต่ประมาณปี 1990 มีเซ็กเมนต์ข้อความคัดลอกเมื่อเขียนดังนั้นฉันจึงไม่แน่ใจด้วยซ้ำว่าทำไมหนังสือและบทความจึงเผยแพร่ "ปัญหาเกี่ยวกับประสิทธิภาพด้วยส้อม" อีกต่อไป
Bruce Ediger

ทุกวันนี้ fork ถูกนำมาใช้ในรูปแบบที่คล้ายคลึงกับ vfork ( openbsd.org/cgi-bin/… ) มันมีประสิทธิภาพไม่ต้องกังวล
Aki

นอกจากนี้โปรดทราบว่ามีการใช้งานมากมายที่คุณไม่ได้เรียกใช้งานหลังจากใช้ส้อม (หรืออย่างน้อยก็ไม่ได้ใช้งานได้ทันที): ลองนึกถึงไพพ์และเว็บเซิร์ฟเวอร์
jfg956

สิ่งที่คุณอาจจะช้า แต่เป็น @cjm พูดว่าดูทางเลือก Microsoft ใช้ CreateProcess พวกเขาต้องใช้หัวข้อก่อน (อาจเป็นสิ่งเดียวที่พวกเขานำไปสู่) เพราะ CreateProcess ช้า (พวกเขาต้องการเธรดเพราะselectแตก แต่นั่นเป็นอีกเรื่องหนึ่ง)
ctrl-alt-delor

คำตอบ:


57

เพื่อลดความซับซ้อนของอินเทอร์เฟซ ทางเลือกในการforkและexecจะเป็นสิ่งที่ต้องการฟังก์ชั่นCreateProcessของ Windows สังเกตว่ามีพารามิเตอร์กี่ตัวCreateProcessและหลายตัวเป็น struct ที่มีพารามิเตอร์มากขึ้น นี้เป็นเพราะทุกอย่างCreateProcessที่คุณอาจต้องการที่จะควบคุมเกี่ยวกับกระบวนการใหม่จะต้องมีการส่งผ่านไปยัง ในความเป็นจริงCreateProcessไม่ได้มีพารามิเตอร์พอดังนั้นไมโครซอฟท์มีการเพิ่มCreateProcessAsUserและCreateProcessWithLogonW

ด้วยfork/execโมเดลคุณไม่จำเป็นต้องใช้พารามิเตอร์เหล่านั้นทั้งหมด execแต่คุณลักษณะบางอย่างของกระบวนการที่จะถูกเก็บไว้ข้าม นี้ช่วยให้คุณforkแล้วเปลี่ยนกระบวนการสิ่งที่คุณต้องการแอตทริบิวต์ (โดยใช้ฟังก์ชั่นเดียวกับที่คุณต้องการใช้ตามปกติ) และจากนั้น execใน Linux forkไม่มีพารามิเตอร์และexecveมีเพียง 3: โปรแกรมที่เรียกใช้บรรทัดคำสั่งที่ให้และสภาพแวดล้อม (มีexecฟังก์ชั่นอื่น ๆแต่พวกมันแค่ล้อมรอบที่execveจัดไว้ให้โดยไลบรารี C เพื่อลดความซับซ้อนกรณีการใช้งานทั่วไป)

forkหากคุณต้องการที่จะเริ่มต้นกระบวนการที่มีไดเรกทอรีปัจจุบันแตกต่างกัน: chdir, exec,

หากคุณต้องการที่จะเปลี่ยนเส้นทาง stdin / stdout: forkใกล้ / execเปิดไฟล์

forkหากคุณต้องการผู้ใช้งานสวิทช์: setuid, exec,

สิ่งเหล่านี้สามารถรวมกันได้ตามต้องการ ถ้าใครมากับรูปแบบใหม่ของแอตทริบิวต์กระบวนการคุณไม่ได้มีการเปลี่ยนแปลงและforkexec

ดังที่กล่าวถึง larsks, Unixes ทันสมัยส่วนใหญ่ใช้ copy-on-write ดังนั้นจึงforkไม่เกี่ยวข้องกับค่าใช้จ่ายที่สำคัญ


16
คำอธิบายที่ยอดเยี่ยม "ผู้ที่ไม่เข้าใจยูนิกซ์ถูกประณามว่าจะคิดค้นสิ่งใหม่ได้ไม่ดี" - Henry Spencer
Kyle Jones

1
ขอบคุณ! คุณมีข้อมูลอ้างอิงโดยบังเอิญหรือไม่?
Ellen Spertus

1
@ Aki, nope, CreateProcess () สร้างกระบวนการใหม่และสร้างมันขึ้นมาใหม่โดยไม่มีการฟอร์ก
psusi

2
แต่จะต้องไม่เท่ากับ CreateProcess () บางแห่งใน Unix? มิฉะนั้นขั้นตอนแรกจะถูกสร้างขึ้นได้อย่างไร? ไม่เหมือนกับเทพเจ้าผู้สร้างในตำนานกระบวนการแรกไม่สามารถแยก () ออกจากความว่างเปล่าได้ ;-)
Steven วันจันทร์

2
@StevenMonday ใช่ แต่มันอยู่ในรหัสเริ่มต้นของเคอร์เนลและไม่สามารถเข้าถึงได้จากภายนอก ไม่ต้องการพารามิเตอร์ทั้งหมดเพราะเกือบทุกอย่างจะถูกเข้ารหัส สามารถสร้างกระบวนการ ID 1 หรือที่รู้จักในกระบวนการเริ่มต้นเท่านั้น หลังจากนั้นกระบวนการจะถูกสร้างโดยการฟอร์กเท่านั้น
cjm

5

ในเติมคำตอบของ CJM ที่สเปก Unix vfork()เดี่ยวกำหนดฟังก์ชั่นที่มีชื่อว่า ฟังก์ชั่นที่ทำงานเช่นส้อมยกเว้นว่ากระบวนการคดเคี้ยวมีพฤติกรรมที่ไม่ได้กำหนดถ้ามันไม่อะไรอื่นนอกจากลองเรียกฟังก์ชั่น familly exec _exit()หรือโทร

ดังนั้นสวยมากเพียงใช้กับพฤติกรรมที่กำหนดคือ:

pid_t ret = vfork();
if(ret == 0)
{
    exec(...);
    _exit(EXIT_FAILURE); //in case exec failed for any reason.
}

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

นอกจากนี้ยังมีposix_spawnฟังก์ชั่นเสริม(และposix_spawnpฟังก์ชั่น) ซึ่งสามารถสร้างกระบวนการใหม่ได้โดยตรง (อนุญาตให้นำไปใช้กับการเรียกใช้ไลบรารีforkและอนุญาตให้ใช้งานexecตัวอย่างได้)

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