ส้อม (เรียกระบบ)

จากวิกิพีเดีย สารานุกรมเสรี
ข้ามไปที่การนำทาง ข้ามไปที่การค้นหา

ใน การ คำนวณโดยเฉพาะอย่างยิ่งในบริบทของ ระบบปฏิบัติการ Unixและลักษณะการทำงานfork คือการดำเนินการที่กระบวนการสร้างสำเนาของตัวเอง เป็นอินเทอร์เฟซที่จำเป็นสำหรับการปฏิบัติตามมาตรฐานข้อกำหนดPOSIX และ Single UNIX โดยปกติจะถูกนำไปใช้เป็นwrapper C Standard Library (libc) ไปยัง fork, clone หรือการเรียกระบบ อื่น ๆของเคอร์เนล Fork เป็นวิธีการหลักในการสร้างกระบวนการบนระบบปฏิบัติการที่เหมือนยูนิกซ์

ภาพรวม

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

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

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

ประวัติ

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

การสื่อสาร

กระบวนการลูกเริ่มต้นด้วยสำเนาของตัวอธิบายไฟล์ ของพา เรนต์ [5]สำหรับการสื่อสารระหว่างกระบวนการ กระบวนการหลักมักจะสร้างหนึ่งหรือหลายไพพ์จากนั้นหลังจากการฟอร์กกระบวนการจะปิดปลายของไพพ์ที่ไม่ต้องการ [6]

รุ่นต่างๆ

ฟอร์ค

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

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

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

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

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

ในทำนองเดียวกัน man page ของ Linux สำหรับ vfork ไม่สนับสนุนการใช้งาน: [7] [ การตรวจสอบล้มเหลว ] [ อภิปราย ]

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

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

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

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

ฟอร์ค

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

โคลน

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

การฟอร์กในระบบปฏิบัติการอื่น

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

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

การใช้งานแอพพลิเคชั่น

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

int หลัก( เป็นโมฆะ) 
{
    pid_t pid = ส้อม();   

    ถ้า( pid == -1 ) {    
        perror ( "ส้อมล้มเหลว" );
        ออก( EXIT_FAILURE );
    }
    อย่างอื่นถ้า( pid == 0 ) {     
        printf ( "สวัสดีจากกระบวนการลูก! \n " );
        _exit ( EXIT_SUCCESS );
    }
    อื่นๆ{ 
        สถานะint ; 
        ( เป็นโมฆะ) waitpid ( pid , & สถานะ, 0 );  
    }
    ส่งคืนEXIT_SUCCESS ; 
}

สิ่งที่ตามมาคือการผ่าโปรแกรมนี้

   pid_t pid = ส้อม();   

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

    ถ้า( pid == -1 ) {    
        perror ( "ส้อมล้มเหลว" );
        ออก( EXIT_FAILURE );
    }

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

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

   อย่างอื่นถ้า( pid == 0 ) {     
      printf ( "สวัสดีจากกระบวนการลูก! \n " );
      _exit ( EXIT_SUCCESS );
   }

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

   อื่นๆ{ 
      สถานะint ; 
      ( เป็นโมฆะ) waitpid ( pid , & สถานะ, 0 );  
   }

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

ดูเพิ่มเติม

อ้างอิง

  1. ^ Nyman, Linus (25 สิงหาคม 2559). "หมายเหตุเกี่ยวกับประวัติของ Fork and Join". พงศาวดาร IEEE ของประวัติศาสตร์คอมพิวเตอร์ 38 (3): 84–87. ดอย : 10.1109/MAHC.2016.34 .
  2. ^ "s3.s จาก Research UNIX " GitHub . 1970.
  3. เคน ทอมป์สันและเดนนิส ริตชี (3 พฤศจิกายน พ.ศ. 2514) "SYS FORK (II)" (PDF) . คู่มือโปรแกรมเมอร์ UNIX ห้องปฏิบัติการเบลล์
  4. ^ ริตชี่ เดนนิส เอ็ม. ; ทอมป์สัน, เคน (กรกฎาคม 1978) "ระบบแบ่งปันเวลาของ UNIX" (PDF ) เบลล์ ซิสเต็ม เทค เจ . เอทีแอนด์ที 57 (6): 1905–1929. ดอย : 10.1002/j.1538-7305.1978.tb02136.x . สืบค้นเมื่อ22 เมษายน 2557 .
  5. ^ a b fork  – การอ้างอิงส่วนต่อประสาน ระบบ, ข้อมูลจำเพาะ UNIX เดี่ยว , ฉบับที่ 7 จากThe Open Group
  6. ^ pipe  – การอ้างอิงส่วนต่อประสาน ระบบ, ข้อมูลจำเพาะ UNIX เดี่ยว , ฉบับที่ 7 จาก The Open Group
  7. ^ a b vfork(2)  –  Linux Programmer's Manual – System Calls
  8. ^ a b "เอกสาร NetBSD: ทำไมต้องใช้ vfork()" แบบดั้งเดิม โครงการNetBSD สืบค้นเมื่อ16 ตุลาคม 2556 .
  9. ^ "vfork(2)". คู่มือโปรแกรมเมอร์ UNIX เวอร์ชัน Virtual VAX- 11 มหาวิทยาลัยแคลิฟอร์เนีย เบิร์กลีย์ ธันวาคม 2522
  10. ^ a b c vfork  – การอ้างอิงส่วนต่อประสาน ระบบ, ข้อมูลจำเพาะ Single UNIX , ฉบับที่ 6 จากThe Open Group
  11. บัค, มอริซ เจ. (1986). การออกแบบระบบปฏิบัติการ UNIX ศิษย์ฮอลล์. น. 291–292. Bibcode : 1986duos.book.....ข .
  12. อรรถเป็น c Nakhimovsky, เกร็ก (2006). "การลดการใช้หน่วยความจำสำหรับการสร้างกระบวนการย่อยของแอปพลิเคชัน " ออราเคิล เทคโนโลยีเน็ตเวิร์ก ออราเคิล คอร์ปอเรชั่น .
  13. ^ การใช้งาน OpenSolaris posix_spawn(): https://sourceforge.net/p/schillix-on/schillix-on/ci/default/tree/usr/src/lib/libc/port/threads/spawn.c
  14. ^ posix_spawn  – การอ้างอิงส่วนต่อประสาน ระบบ, ข้อมูลจำเพาะ UNIX เดี่ยว , ฉบับที่ 7 จาก The Open Group
  15. ^ fork(2)  –  คู่มือโปรแกรมเมอร์ แผน 9เล่ม 1
  16. ^ intro(2)  –  คู่มือโปรแกรมเมอร์ แผน 9เล่ม 1
  17. ^ rfork(2)  – คู่มือการโทรระบบ FreeBSD
  18. อรรถเป็น Torvalds, Linus (1999). "ขอบลินุกซ์" . โอเพ่นซอร์ส: เสียงจากการปฏิวัติโอเพ่นซอร์ส โอเรลลี่. ISBN 978-1-56592-582-3.
  19. ^ "z/VM > z/VM 6.2.0 > Application Programming > z/VM V6R2 OpenExtensions POSIX Conformance Document > POSIX.1 Conformance Document > Section 3. Process Primitives > 3.1 Process Creation and Execution > 3.1.1 Process Creation " ไอบีเอ็ม. สืบค้นเมื่อ21 เมษายน 2558 .