กลับไปหน้าบทความ

อ่าน 6 นาที

Fork (การเรียกใช้ระบบ)

ใน ด้าน การคำนวณforkคือการดำเนินการที่กระบวนการสร้างสำเนาของตัวเอง โดยปกติแล้วจะถูกนำไปใช้เป็นตัวห่อไลบรารีมาตรฐาน C สำหรับ fork, clone หรือการเรียกใช้ระบบ อื่นๆ...

Fork (การเรียกใช้ระบบ)

ใน ด้าน การคำนวณforkคือการดำเนินการที่กระบวนการสร้างสำเนาของตัวเอง โดยปกติแล้วจะถูกนำไปใช้เป็นตัวห่อไลบรารีมาตรฐาน C สำหรับ fork, clone หรือการเรียกใช้ระบบ อื่นๆ ของเคอร์เนลเป็นเวลาหลายปีที่ fork เป็นวิธีการหลักในการสร้างกระบวนการบน ระบบ ปฏิบัติการ Unixและ ระบบปฏิบัติการ ที่คล้าย Unixและยังคงเป็นอินเทอร์เฟซที่จำเป็นสำหรับการปฏิบัติตามPOSIXแม้จะเป็นเช่นนั้น แต่ในไม่กี่ปีที่ผ่านมาก็ไม่เป็นที่นิยมเนื่องจากข้อบกพร่องต่างๆ รวมถึงประสิทธิภาพที่ไม่ดี การขาดความปลอดภัย ของเธรดและสถานะที่เป็นแหล่งที่มาทั่วไปของช่องโหว่ด้านความปลอดภัย [ 1 ]

ภาพรวม

ในระบบปฏิบัติการแบบมัลติทาสก์กระบวนการ (โปรแกรมที่กำลังทำงาน) จำเป็นต้องมีวิธีการสร้างกระบวนการใหม่ เช่น เพื่อเรียกใช้โปรแกรมอื่น โดยทั่วไปแล้ว คำสั่ง Fork และรูปแบบต่างๆ ของมันเป็นวิธีเดียวในการทำเช่นนั้นในระบบที่คล้าย Unix สำหรับกระบวนการที่จะเริ่มต้นการทำงานของโปรแกรมอื่น กระบวนการนั้นจะทำการ Fork เพื่อสร้างสำเนาของตัวเองก่อน จากนั้น สำเนาที่เรียกว่า " กระบวนการลูก " จะทำการเปลี่ยนแปลงสภาพแวดล้อมที่จำเป็นสำหรับกระบวนการลูก แล้วเรียกใช้ ระบบคำสั่ง execเพื่อแทนที่ตัวเองด้วยโปรแกรมใหม่: มันจะหยุดการทำงานของโปรแกรมเดิมและเริ่มการทำงานของโปรแกรมใหม่ (หรือในกรณีที่หายากกว่านั้น กระบวนการลูกอาจไม่เรียกใช้execและดำเนินการต่อไปในฐานะกระบวนการแยกต่างหาก สำหรับฟังก์ชันอื่นๆ ของโปรแกรมเดิม)

การดำเนินการ fork สร้างพื้นที่แอดเดรส แยกต่างหาก สำหรับกระบวนการลูก กระบวนการลูกจะมีสำเนาที่เหมือนกันทุกประการของส่วนหน่วยความจำทั้งหมดของกระบวนการแม่ ในระบบปฏิบัติการ UNIX รุ่นใหม่ๆ ที่ใช้ โมเดล หน่วยความจำเสมือนจากSunOS -4.0 จะมีการใช้หลักการ copy-on-writeและไม่จำเป็นต้องคัดลอกหน่วยความจำทางกายภาพจริงๆ แต่หน้าหน่วยความจำเสมือนในทั้งสองกระบวนการอาจอ้างอิงถึงหน้าหน่วยความจำทางกายภาพ เดียวกัน จนกว่ากระบวนการใดกระบวนการหนึ่งจะเขียนลงในหน้านั้น จากนั้นจึงจะทำการคัดลอก การปรับปรุงประสิทธิภาพนี้มีความสำคัญในกรณีทั่วไปที่ใช้ fork ร่วมกับ exec เพื่อเรียกใช้โปรแกรมใหม่ โดยทั่วไปแล้ว กระบวนการลูกจะดำเนินการเพียงเล็กน้อยก่อนที่จะหยุดการทำงานของโปรแกรมเดิมเพื่อเริ่มโปรแกรมใหม่ และต้องการโครงสร้างข้อมูล ของกระบวนการแม่เพียงเล็กน้อยหรือไม่ต้องการ เลย

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

ประวัติของ fork ย้อนกลับไปในช่วงทศวรรษ 1960 โดยหนึ่งในเอกสารอ้างอิงแรกสุดเกี่ยวกับแนวคิด fork ปรากฏในA Multiprocessor System DesignโดยMelvin Conwayซึ่งตีพิมพ์ในปี 1962 [ 2 ]บทความของ Conway เป็นแรงบันดาลใจให้L. Peter Deutschนำ fork ไปใช้ในระบบแบ่งเวลา GENIEซึ่งแนวคิดนี้ถูกยืมโดยKen Thompsonสำหรับการปรากฏตัวครั้งแรก[ 3 ] ใน Research Unix [ 4 ] [ 5 ] ต่อมา fork กลายเป็นอินเทอร์เฟซมาตรฐานในPOSIX [ 6 ]

ทางเทคนิค

ตัวอย่าง

ตัวอย่างโปรแกรม "Hello, World!" ต่อไปนี้เป็นตัวอย่าง ที่แสดงกลไกการทำงานของ ระบบเรียกใช้ `fork`ใน ภาษา Cโปรแกรมจะแยกออกเป็นสองกระบวนการ โดยแต่ละกระบวนการจะตัดสินใจว่าจะทำงานอะไรโดยอิงจากค่าที่ส่งคืนจากระบบเรียกใช้ `fork` โค้ดส่วนที่ไม่จำเป็นเช่นการรวมไฟล์เฮดเดอร์ได้ถูกตัดออกไปแล้ว

#include <stdio.h> #include <stdlib.h> #include <unistd.h>int main ( void ) { pid_t pid = fork ();ถ้าpid == -1 ให้แสดงข้อความ" fork failed" แล้วส่งค่าEXIT_FAILURE กลับมามิฉะนั้นถ้าpid == 0 ให้แสดงข้อความ" Hello from the child process! \ n " แล้วส่งค่าEXIT_SUCCESS กลับมามิฉะนั้นให้ดึงค่าstatus ของpid และwaitpid กลับมาส่งค่าEXIT_SUCCESS กลับมา

ต่อไปนี้คือการวิเคราะห์รายละเอียดของโปรแกรมนี้

pid_t pid = fork ();

คำสั่งแรกในฟังก์ชันmain เรียกใช้ระบบ forkเพื่อแบ่งการทำงานออกเป็นสองกระบวนการ ค่าที่ส่งคืนจากforkจะถูกบันทึกไว้ในตัวแปรชนิดpid_tซึ่งเป็นชนิดข้อมูล POSIX สำหรับตัวระบุโปรเซส (PID)

ถ้า( pid == -1 ) { perror ( "fork failed" ); return EXIT_FAILURE ; }

ค่าลบหนึ่งบ่งชี้ว่ามีข้อผิดพลาดในการ สร้างกระบวนการใหม่ (fork) : ไม่มีการสร้างกระบวนการใหม่ ดังนั้นจึงมีการแสดงข้อความแสดงข้อผิดพลาด

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

else if ( pid == 0 ) { printf ( "สวัสดีจากกระบวนการลูก! \n " ); return EXIT_SUCCESS ; }

ในกระบวนการลูก ค่าที่ส่งกลับจะปรากฏเป็นศูนย์ (ซึ่งเป็นตัวระบุโปรเซส ที่ไม่ถูกต้อง ) กระบวนการลูกจะพิมพ์ข้อความทักทายที่ต้องการ จากนั้นจึงออกจากโปรแกรม (ด้วยเหตุผลทางเทคนิค ต้องใช้ฟังก์ชัน _exit ของ POSIX แทน ฟังก์ชัน exit มาตรฐานของภาษา C )

มิฉะนั้น{ int status ; waitpid ( pid , & status , 0 ); }

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

การสื่อสาร

กระบวนการลูกเริ่มต้นด้วยสำเนาของตัวอธิบายไฟล์ของกระบวนการแม่[ 6 ]สำหรับการสื่อสารระหว่างกระบวนการด้วยการแลกเปลี่ยนข้อมูลและการซิงโครไนซ์ระหว่างกระบวนการแม่และกระบวนการลูกสามารถใช้ท่อ ได้ [ 7 ]กระบวนการแม่มักจะสร้างท่อหนึ่งหรือหลายท่อ จากนั้นหลังจากแยกกระบวนการแล้วจะปิดปลายท่อที่ไม่ต้องการ[ 7 ]เพื่อแบ่งปันตัวแปรเดียวกันระหว่างกระบวนการแม่และกระบวนการลูกต้องใช้การแมปหน่วยความจำหรือหน่วยความจำร่วม[ 8 ]

ตัวแปร

วีฟอร์ค

vfork เป็นรูปแบบหนึ่งของ fork ที่มี ข้อกำหนดการเรียกใช้แบบเดียวกันและความหมายที่คล้ายคลึงกันมาก แต่ใช้ได้เฉพาะในสถานการณ์ที่จำกัดเท่านั้น มีต้นกำเนิดมาจากUnix เวอร์ชัน3BSD [ 9 ] [ 10 ] [ 11 ]ซึ่งเป็น Unix รุ่นแรกที่รองรับหน่วยความจำเสมือน ได้รับการกำหนดมาตรฐานโดย POSIX ซึ่งอนุญาตให้ vfork มีพฤติกรรมเหมือนกับ fork ทุกประการ แต่ถูกทำเครื่องหมายว่าล้าสมัยในฉบับปี 2004 [ 12 ]และถูกแทนที่ด้วยposix_spawn () (ซึ่งโดยทั่วไปจะถูกนำไปใช้ผ่าน vfork) ในฉบับต่อมา

เมื่อมีการเรียกใช้ระบบ vfork กระบวนการหลักจะถูกระงับจนกว่ากระบวนการย่อยจะเสร็จสิ้นการทำงานหรือถูกแทนที่ด้วยอิมเมจที่สามารถเรียกใช้งานได้ใหม่ผ่านการเรียกใช้ระบบตระกูล " exec " กระบวนการย่อยจะยืม การตั้งค่า หน่วยการจัดการหน่วยความจำจากกระบวนการหลัก และหน้าหน่วยความจำจะถูกใช้ร่วมกันระหว่างกระบวนการหลักและกระบวนการย่อยโดยไม่มีการคัดลอก และโดยเฉพาะอย่างยิ่งไม่มีความหมายของcopy-on-write [ 12 ]ดังนั้น หากกระบวนการย่อยทำการแก้ไขในหน้าหน่วยความจำที่ใช้ร่วมกัน จะไม่มีการสร้างหน้าใหม่ และหน้าหน่วยความจำที่แก้ไขแล้วจะมองเห็นได้โดยกระบวนการหลักด้วย เนื่องจากไม่มีการคัดลอกหน้าหน่วยความจำ (ซึ่งใช้หน่วยความจำเพิ่มเติม) เทคนิคนี้จึงเป็นการเพิ่มประสิทธิภาพเหนือการใช้ fork แบบธรรมดาในสภาพแวดล้อมแบบ full-copy เมื่อใช้ร่วมกับ exec ใน POSIX การใช้ vfork เพื่อวัตถุประสงค์ใดๆ ยกเว้นเป็นการเตรียมการก่อนการเรียกใช้ฟังก์ชันจากตระกูล exec โดยตรง (และการดำเนินการอื่นๆ ที่เลือกไว้บางส่วน) จะทำให้เกิดพฤติกรรมที่ไม่กำหนด[ 12 ] เช่นเดียวกับ vfork กระบวนการย่อย จะยืมโครงสร้างข้อมูลแทนที่จะคัดลอก vfork ยังคงเร็วกว่า fork ที่ใช้กลไก copy on write

ก่อนการเปิดตัว System VR4 นั้น System Vไม่รองรับการเรียกใช้ฟังก์ชันนี้ เนื่องจากฟังก์ชันการแชร์หน่วยความจำที่เกิดขึ้นนั้นมีโอกาสเกิดข้อผิดพลาดสูง:

vforkไม่คัดลอกตารางเพจ ดังนั้นจึงเร็วกว่า การใช้งาน fork ของ System V แต่กระบวนการลูกจะทำงานในพื้นที่แอดเดรสทางกายภาพเดียวกันกับกระบวนการแม่ (จนกว่าจะมีการเรียกใช้execหรือexit ) และอาจเขียนทับข้อมูลและสแต็กของกระบวนการแม่ได้ สถานการณ์อันตรายอาจเกิดขึ้นได้หากโปรแกรมเมอร์ใช้vforkอย่างไม่ถูกต้อง ดังนั้นความรับผิดชอบในการเรียกใช้vforkจึงอยู่ที่โปรแกรมเมอร์ ความแตกต่างระหว่างแนวทางของ System V และแนวทางของ BSD นั้นเป็นเรื่องของปรัชญา: เคอร์เนลควรซ่อนลักษณะเฉพาะของการใช้งานจากผู้ใช้ หรือควรอนุญาตให้ผู้ใช้ที่มีความเชี่ยวชาญมีโอกาสใช้ประโยชน์จากการใช้งานเพื่อทำหน้าที่เชิงตรรกะได้อย่างมีประสิทธิภาพมากขึ้น?

— มอริซ เจ. บาค[ 13 ]

ในทำนองเดียวกัน หน้าคู่มือ Linux สำหรับ vfork ไม่แนะนำให้ใช้อย่างยิ่ง: [ 9 ]

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

ปัญหาอื่นๆ ของvforkได้แก่การติดตายที่อาจเกิดขึ้นใน โปรแกรม มัลติเธรดเนื่องจากการโต้ตอบกับการเชื่อมโยงแบบไดนามิก [ 14 ] เพื่อทดแทน อินเทอร์เฟซ vforkนั้น POSIX ได้แนะนำ ตระกูลฟังก์ชัน posix_spawnซึ่งรวมการกระทำของ fork และ exec เข้าด้วยกัน ฟังก์ชันเหล่านี้อาจถูกนำไปใช้เป็นรูทีนไลบรารีในแง่ของforkดังที่ทำใน Linux [ 14 ]หรือในแง่ของvforkเพื่อประสิทธิภาพที่ดีขึ้น ดังที่ทำใน Solaris [ 14 ] [ 15 ]แต่ข้อกำหนดของ POSIX ระบุว่าฟังก์ชันเหล่านี้ "ได้รับการออกแบบให้เป็นการดำเนินการของเคอร์เนล " โดยเฉพาะอย่างยิ่งสำหรับระบบปฏิบัติการที่ทำงานบนฮาร์ดแวร์ที่มีข้อจำกัดและระบบเรียลไทม์[ 16 ]

แม้ว่าการใช้งาน 4.4BSD จะกำจัดการใช้งาน vfork ออกไป ทำให้ vfork มีพฤติกรรมเหมือนกับ fork แต่ต่อมาก็ได้นำกลับมาใช้ใน ระบบปฏิบัติการ NetBSD อีกครั้ง ด้วยเหตุผลด้านประสิทธิภาพ[ 10 ]

ระบบปฏิบัติการฝังตัวบางระบบ เช่นuClinuxละเว้นการใช้ fork และใช้เพียง vfork เท่านั้น เนื่องจากจำเป็นต้องทำงานบนอุปกรณ์ที่ไม่สามารถใช้ copy-on-write ได้เนื่องจากขาดหน่วยจัดการหน่วยความจำ

อาร์ฟอร์ค

ระบบปฏิบัติการ Plan 9ซึ่งสร้างโดยนักออกแบบ Unix มีฟังก์ชัน fork เป็นรูปแบบหนึ่งของฟังก์ชันใหม่ที่เรียกว่า "rfork" ซึ่งอนุญาตให้มีการแบ่งปันทรัพยากรอย่างละเอียดระหว่างกระบวนการแม่และกระบวนการลูก รวมถึงพื้นที่แอดเดรส (ยกเว้น ส่วนของ สแต็กซึ่งเป็นเอกลักษณ์เฉพาะของแต่ละกระบวนการ) ตัวแปรสภาพแวดล้อมและเนมสเปซของระบบไฟล์[ 17 ]ทำให้เป็นอินเทอร์เฟซที่เป็นหนึ่งเดียวสำหรับการสร้างทั้งกระบวนการและเธรดภายในกระบวนการเหล่านั้น[ 18 ]ทั้งFreeBSD [ 19 ]และIRIXได้นำระบบเรียก rfork จาก Plan 9 มาใช้ โดย IRIX เปลี่ยนชื่อเป็น "sproc" [ 20 ]

โคลน

cloneเป็นการเรียกใช้ระบบในเคอร์เนล Linuxที่สร้างกระบวนการลูกซึ่งอาจแบ่งปันส่วนต่างๆ ของบริบท การดำเนินการ กับกระบวนการแม่ เช่นเดียวกับ rfork ของ FreeBSD และ sproc ของ IRIX clone ของ Linux ได้รับแรงบันดาลใจจาก rfork ของ Plan 9 และสามารถใช้ในการสร้างเธรดได้ (แม้ว่าโดยทั่วไปแล้วโปรแกรมเมอร์แอปพลิเคชันจะใช้อินเทอร์เฟซระดับสูงกว่า เช่นpthreadsซึ่งสร้างขึ้นบน clone) คุณสมบัติ "สแต็กแยก" จาก Plan 9 และ IRIX ถูกละเว้นเนื่องจาก (ตามที่Linus Torvalds กล่าว ) ทำให้เกิดโอเวอร์เฮดมากเกินไป[ 20 ]

ในระบบปฏิบัติการอื่นๆ การแยกกระบวนการ (Forking)

ในการออกแบบ ระบบปฏิบัติการ VMS ดั้งเดิม (ปี 1977) การดำเนินการคัดลอกที่ตามมาด้วยการเปลี่ยนแปลงเนื้อหาของแอดเดรสเฉพาะบางส่วนสำหรับกระบวนการใหม่ เช่นเดียวกับการแยกกระบวนการ (forking) นั้นถือว่ามีความเสี่ยง ข้อผิดพลาดในสถานะของกระบวนการปัจจุบันอาจถูกคัดลอกไปยังกระบวนการลูก ดังนั้นจึงใช้คำอุปมาเรื่องการสร้างกระบวนการใหม่ (process spawning) กล่าวคือ ส่วนประกอบแต่ละส่วนของโครงสร้างหน่วยความจำของกระบวนการใหม่จะถูกสร้างขึ้นใหม่ทั้งหมดตั้งแต่เริ่มต้น คำ อุปมา เรื่องการสร้างกระบวนการใหม่นี้ ได้รับการนำไปใช้ในระบบปฏิบัติการของ Microsoft ในภายหลัง (ปี 1993)

ส่วนประกอบความเข้ากันได้ของ POSIX ของVM/CMS (OpenExtensions) ให้การใช้งาน fork ที่จำกัดมาก ซึ่งกระบวนการหลักจะถูกระงับในขณะที่กระบวนการย่อยทำงาน และกระบวนการย่อยและกระบวนการหลักใช้พื้นที่แอดเดรสร่วมกัน[ 21 ]โดยพื้นฐานแล้วนี่คือvforkที่ติดป้ายกำกับว่าเป็นfork (สิ่งนี้ใช้ได้กับระบบปฏิบัติการแขกของ CMS เท่านั้น ระบบปฏิบัติการแขก VM อื่นๆ เช่น Linux ให้ฟังก์ชัน fork มาตรฐาน)

ดูเพิ่มเติม

ดึงข้อมูลมาจาก " https://en.wikipedia.org/w/index.php?title=Fork_(system_call)&oldid=1360024736#Clone "

สรุปเนื้อหา

ข้อมูลสำคัญจากบทความ

ข้อมูลสำคัญเกี่ยวกับ Fork (การเรียกใช้ระบบ)

ใน ด้าน การคำนวณforkคือการดำเนินการที่กระบวนการสร้างสำเนาของตัวเอง โดยปกติแล้วจะถูกนำไปใช้เป็นตัวห่อไลบรารีมาตรฐาน C สำหรับ fork, clone หรือการเรียกใช้ระบบ อื่นๆ...

ภาพรวม

ใน ระบบปฏิบัติการแบบมัลติทาสก์ กระบวนการ (โปรแกรมที่กำลังทำงาน) จำเป็นต้องมีวิธีการสร้างกระบวนการใหม่ เช่น เพื่อเรียกใช้โปรแกรมอื่น โดยทั่วไปแล้ว คำสั่ง Fork และรูปแบบต่างๆ ของมันเป็นวิธีเดียวในการทำเช่นนั้นในระบบที่คล้าย Unix...

ตัวอย่าง

ตัวอย่าง โปรแกรม "Hello, World!" ต่อไปนี้เป็นตัวอย่าง ที่แสดงกลไกการทำงานของ ระบบเรียกใช้ `fork` ใน ภาษา C โปรแกรมจะแยกออกเป็นสองกระบวนการ โดยแต่ละกระบวนการจะตัดสินใจว่าจะทำงานอะไรโดยอิงจากค่าที่ส่งคืนจากระบบเรียกใช้ `fork` โค้ดส่วนที่ไม่จำเป็น เช่น...

การสื่อสาร

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