จุดประสงค์ของ fork () คืออะไร?


88

ในหลายโปรแกรมและหน้าคนของ Linux ฉันเคยเห็นโค้ดที่ใช้fork(). ทำไมเราต้องใช้fork()และจุดประสงค์คืออะไร?


151
เพื่อให้บรรดานักปรัชญาการรับประทานอาหารไม่อดอยาก
kenj0418

คำตอบ:


109

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

นี่คือตัวอย่างการใช้งานบางส่วนของfork:

  1. เชลล์ของคุณใช้forkเพื่อรันโปรแกรมที่คุณเรียกใช้จากบรรทัดคำสั่ง
  2. เว็บเซิร์ฟเวอร์เช่นapacheใช้forkเพื่อสร้างกระบวนการของเซิร์ฟเวอร์หลายรายการซึ่งแต่ละกระบวนการจะจัดการคำขอในพื้นที่ที่อยู่ของตัวเอง หากหน่วยความจำเสียหรือรั่วหน่วยความจำอื่น ๆ จะไม่ได้รับผลกระทบดังนั้นจึงทำหน้าที่เป็นกลไกในการยอมรับข้อผิดพลาด
  3. Google Chromeใช้forkเพื่อจัดการแต่ละหน้าภายในกระบวนการแยกกัน วิธีนี้จะป้องกันไม่ให้โค้ดฝั่งไคลเอ็นต์ในหน้าเดียวนำเบราว์เซอร์ทั้งหมดของคุณลง
  4. forkใช้เพื่อวางกระบวนการในโปรแกรมคู่ขนานบางโปรแกรม (เช่นเดียวกับที่เขียนโดยใช้MPI ) โปรดทราบว่าสิ่งนี้แตกต่างจากการใช้เธรดซึ่งไม่มีพื้นที่แอดเดรสของตัวเองและมีอยู่ภายในกระบวนการ
  5. ภาษาสคริปต์ใช้forkทางอ้อมเพื่อเริ่มกระบวนการย่อย ตัวอย่างเช่นทุกครั้งที่คุณใช้คำสั่งเช่นsubprocess.Popenใน Python คุณจะforkต้องประมวลผลลูกและอ่านผลลัพธ์ สิ่งนี้ทำให้โปรแกรมสามารถทำงานร่วมกันได้

การใช้งานforkในเชลล์โดยทั่วไปอาจมีลักษณะดังนี้:

เชลล์สร้างกระบวนการย่อยโดยใช้execและรอให้มันเสร็จสิ้นจากนั้นดำเนินการต่อด้วยการดำเนินการของตัวเอง สังเกตว่าคุณไม่จำเป็นต้องใช้ส้อมด้วยวิธีนี้ คุณสามารถสร้างกระบวนการย่อยจำนวนมากได้เสมอเนื่องจากโปรแกรมคู่ขนานอาจทำและแต่ละโปรแกรมอาจรันโปรแกรมพร้อมกัน โดยทั่วไปเวลาที่คุณกำลังสร้างกระบวนการใหม่ในระบบ Unix, fork()คุณกำลังใช้ สำหรับเทียบเท่าของ Windows CreateProcessดูที่

หากคุณต้องการตัวอย่างเพิ่มเติมและคำอธิบายที่ยาวขึ้นWikipediaมีบทสรุปที่ดี และนี่คือสไลด์บางส่วนเกี่ยวกับวิธีการทำงานของกระบวนการเธรดและการทำงานพร้อมกันในระบบปฏิบัติการสมัยใหม่


Bullet 5: 'มัก'? 'บ่อย' เท่านั้น? คนไหนไม่ใช้มันหรือไม่ใช้ fork () ภายใต้สถานการณ์ใด - บนระบบที่รองรับ fork () นั่นคือ
Jonathan Leffler

19
แปลกพอสมควรเรียกว่า CreateProcess () - พวกบ้า Windows :-)
paxdiablo

2
ไม่เคยตระหนักถึงตอนนี้ว่า "เชลล์ใช้ส้อมเพื่อรันโปรแกรมที่คุณเรียกใช้จากบรรทัดคำสั่ง"!
Lazer

1
ลิงก์ของสไลด์เสีย
piertoni

1
คำตอบทั้งหมดบอกว่าfork()เป็นวิธีที่จะสร้างกระบวนการใหม่ในยูนิกซ์ แต่จะอวดความรู้ที่มีอยู่อย่างน้อยหนึ่งอื่น ๆposix_spawn():
Davislor

15

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

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

สำหรับเหตุผลที่คุณสร้างกระบวนการใหม่นั่นคือวิธีที่ระบบปฏิบัติการของคุณสามารถทำหลายอย่างในเวลาเดียวกันได้ นั่นเป็นเหตุผลที่คุณสามารถเรียกใช้โปรแกรมและในขณะที่กำลังทำงานอยู่ให้เปลี่ยนไปใช้หน้าต่างอื่นและทำอย่างอื่น


@varDumper จับดี!
Daniel C. Sobral

9

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

หากค่าที่ส่งคืนเป็น 0 คุณจะรู้ว่าคุณเป็นกระบวนการย่อยและหากค่าที่ส่งคืนเป็นตัวเลข (ซึ่งเป็นรหัสกระบวนการย่อย) แสดงว่าคุณเป็นผู้ปกครอง (และถ้าเป็นจำนวนลบแสดงว่าส้อมล้มเหลวและไม่มีการสร้างกระบวนการย่อย)

http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html


1
เว้นแต่ค่าที่ส่งคืนจะเป็น -1 ซึ่งในกรณีนี้ fork () ล้มเหลว
Jonathan Leffler

8

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

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


6

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


ทำไมคุณสร้างลูกที่เหมือนกับพ่อแม่ใช้อะไร?

1
ก็เหมือนกับการสร้างกองทัพ VS ทหารคนเดียว คุณแยกเพื่อให้โปรแกรมของคุณสามารถจัดการคำขอได้มากขึ้นในเวลาเดียวกันแทนที่จะเป็นทีละรายการ
cloudhead

fork () ส่งคืน 0 บนเด็กและ pid ของเด็กบนพาเรนต์ จากนั้นเด็กสามารถใช้การเรียกเช่น exec () เพื่อแทนที่สถานะด้วยโปรแกรมใหม่ นี่คือวิธีการเปิดตัวโปรแกรม
Todd Gamblin

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

2
@kar: เมื่อคุณมีสองกระบวนการพวกเขาสามารถดำเนินการต่อแยกกันจากที่นั่นและหนึ่งในนั้นสามารถแทนที่ตัวเอง (exex ()) ด้วยโปรแกรมอื่นได้ทั้งหมด
Vatine

4

คุณอาจไม่จำเป็นต้องใช้ส้อมในการเขียนโปรแกรมแบบวันต่อวันหากคุณกำลังเขียนแอปพลิเคชัน

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

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

คุณสามารถเรียกใช้โปรแกรมอื่นแบบอะซิงโครนัสได้ด้วย แต่ฉันจำวิธีไม่ได้

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


ขอบคุณสำหรับsystem(). ฉันอ่านเกี่ยวกับfork()เพราะฉันต้องการให้รหัส C ของฉันเรียกใช้สคริปต์ python
Bean Taxi

4

ส้อมสร้างกระบวนการใหม่ หากไม่มีทางแยกคุณจะมีระบบยูนิกซ์ที่สามารถรันได้เฉพาะ init


4

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

ถ้า fork () ส่งกลับค่าลบแสดงว่าการสร้างโปรเซสลูกไม่สำเร็จ fork () คืนค่าศูนย์ให้กับกระบวนการลูกที่สร้างขึ้นใหม่ fork () ส่งคืนค่าบวก ID กระบวนการของกระบวนการย่อยไปยังพาเรนต์ ID กระบวนการที่ส่งคืนเป็นประเภท pid_t ที่กำหนดใน sys / types.h โดยปกติ ID กระบวนการเป็นจำนวนเต็ม ยิ่งไปกว่านั้นกระบวนการสามารถใช้ฟังก์ชัน getpid () เพื่อดึง ID กระบวนการที่กำหนดให้กับกระบวนการนี้ ดังนั้นหลังจากระบบเรียกใช้ fork () การทดสอบอย่างง่ายสามารถบอกได้ว่ากระบวนการใดเป็นลูก โปรดทราบว่า Unix จะทำสำเนาที่ถูกต้องของพื้นที่ที่อยู่ของผู้ปกครองและมอบให้กับเด็ก ดังนั้นกระบวนการแม่และลูกจึงมีช่องว่างที่อยู่แยกกัน

ให้เราทำความเข้าใจพร้อมตัวอย่างเพื่อให้ประเด็นข้างต้นชัดเจน ตัวอย่างนี้ไม่แยกความแตกต่างของกระบวนการหลักและกระบวนการย่อย

สมมติว่าโปรแกรมข้างต้นรันจนถึงจุดที่เรียกเพื่อ fork ()

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

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

เหตุผลของการใช้ write มากกว่า printf คืออะไร? เป็นเพราะ printf () เป็น "buffered" หมายถึง printf () จะจัดกลุ่มผลลัพธ์ของกระบวนการเข้าด้วยกัน ในขณะที่บัฟเฟอร์เอาต์พุตสำหรับกระบวนการพาเรนต์เด็กอาจใช้ printf เพื่อพิมพ์ข้อมูลบางอย่างซึ่งจะถูกบัฟเฟอร์ด้วย ด้วยเหตุนี้เนื่องจากผลลัพธ์จะไม่ถูกส่งไปยังหน้าจอในทันทีคุณอาจไม่ได้ลำดับที่ถูกต้องของผลลัพธ์ที่คาดหวัง ที่แย่กว่านั้นผลลัพธ์จากทั้งสองกระบวนการอาจผสมกันในรูปแบบแปลก ๆ เพื่อแก้ไขปัญหานี้คุณอาจพิจารณาใช้การเขียนแบบ "ไม่มีบัฟเฟอร์"

หากคุณเรียกใช้โปรแกรมนี้คุณอาจเห็นสิ่งต่อไปนี้บนหน้าจอ:

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


4
แทนที่จะคัดลอกวางข้อความคุณสามารถแสดงความคิดเห็นลิงก์: csl.mtu.edu/cs4411.ck/www/NOTES/process/fork/create.html
chaitanya lakkundi

3

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


3

Fork () ใช้เพื่อสร้างกระบวนการใหม่ตามที่ทุกคนเขียนไว้

นี่คือรหัสของฉันที่สร้างกระบวนการในรูปแบบของต้นไม้ไบนารี ....... มันจะขอให้สแกนจำนวนระดับที่คุณต้องการสร้างกระบวนการในต้นไม้ไบนารี

เอาท์พุท


2

อันดับแรกต้องเข้าใจว่าการเรียกระบบ fork () คืออะไร ให้ฉันอธิบาย

  1. การเรียกระบบ fork () สร้างกระบวนการหลักที่ซ้ำกันทำให้ซ้ำกันของสแต็กหลักฮีปข้อมูลที่เตรียมใช้งานข้อมูลที่ไม่ได้กำหนดค่าเริ่มต้นและแบ่งปันรหัสในโหมดอ่านอย่างเดียวกับกระบวนการหลัก

  2. การเรียกระบบ Fork จะคัดลอกหน่วยความจำบนพื้นฐานการคัดลอกเมื่อเขียนหมายถึงเด็กสร้างในหน้าหน่วยความจำเสมือนเมื่อมีความต้องการในการคัดลอก

ตอนนี้วัตถุประสงค์ของส้อม ():

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

1

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

fork()ยังคงถูกใช้โดยแอปพลิเคชันเซิร์ฟเวอร์บางตัวซึ่งส่วนใหญ่เป็นแอปพลิเคชันที่รันเป็นรูทบนเครื่อง * NIX ที่ยกเลิกสิทธิ์ก่อนประมวลผลคำขอของผู้ใช้ ยังมี usecases อื่น ๆ อยู่บ้าง แต่ตอนนี้คนส่วนใหญ่ย้ายไปใช้ multithreading แล้ว


2
ฉันไม่เข้าใจการรับรู้ที่ว่า "คนส่วนใหญ่" เปลี่ยนไปใช้มัลติเธรด กระบวนการอยู่ที่นี่และเธรดก็เช่นกัน ไม่มีใคร "ย้าย" จากอย่างใดอย่างหนึ่ง ในการเขียนโปรแกรมแบบขนานรหัสที่ใหญ่ที่สุดและพร้อมกันมากที่สุดคือโปรแกรมหลายกระบวนการหน่วยความจำแบบกระจาย (เช่น MapReduce และ MPI) ถึงกระนั้นคนส่วนใหญ่จะเลือกใช้ OpenMP หรือกระบวนทัศน์หน่วยความจำที่ใช้ร่วมกันสำหรับเครื่องมัลติคอร์และ GPU กำลังใช้เธรดในทุกวันนี้ แต่ยังมีอีกมากมายที่นอกเหนือจากนั้น ฉันพนันได้เลยว่าผู้เขียนโค้ดในไซต์นี้พบกระบวนการขนานกันทางฝั่งเซิร์ฟเวอร์มากกว่าสิ่งที่เป็นแบบมัลติเธรด
Todd Gamblin

1

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

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

ในระบบปฏิบัติการ Windows ตรงกันข้ามโปรแกรมเมอร์ต้องใช้ฟังก์ชัน CreateProcess ซึ่งซับซ้อนกว่ามากและต้องมีการเติมโครงสร้างที่หลากหลายเพื่อกำหนดพารามิเตอร์ของกระบวนการใหม่

ดังนั้นเพื่อสรุปเหตุผลของการฟอร์ก (เทียบกับการดำเนินการ) คือความเรียบง่ายในการสร้างกระบวนการใหม่


0

การเรียกระบบ Fork () ใช้เพื่อสร้างกระบวนการย่อย มันซ้ำกันแน่นอนกับกระบวนการหลัก Fork คัดลอกส่วนสแต็กส่วนฮีปส่วนข้อมูลตัวแปรสภาพแวดล้อมอาร์กิวเมนต์บรรทัดคำสั่งจากพาเรนต์

อ้างอิง: http://man7.org/linux/man-pages/man2/fork.2.html


0

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

  • เด็กมี PID ที่ไม่ซ้ำกันเหมือนกับกระบวนการอื่น ๆ ที่ทำงานในระบบปฏิบัติการ

  • ชายด์มี ID กระบวนการหลักซึ่งเหมือนกับ PID ของ
    กระบวนการที่สร้างขึ้น

  • การใช้ทรัพยากรและตัวนับเวลาของ CPU ถูกรีเซ็ตเป็นศูนย์ในกระบวนการย่อย

  • ชุดสัญญาณที่รอดำเนินการในชุดย่อยว่างเปล่า

  • เด็กไม่ได้รับช่วงเวลาใด ๆ จากผู้ปกครอง

ตัวอย่าง:

ตอนนี้เมื่อรวบรวมและเรียกใช้โค้ดด้านบน:

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