ฉันมีความสับสนเกี่ยวกับส้อมและโคลน ฉันได้เห็นว่า:
fork เป็นกระบวนการและโคลนสำหรับเธรด
fork เพียงเรียกการโคลน clone ถูกใช้สำหรับกระบวนการและเธรดทั้งหมด
ถูกต้องหรือไม่ อะไรคือความแตกต่างระหว่าง 2 syscalls ที่มีเคอร์เนล 2.6 Linux?
ฉันมีความสับสนเกี่ยวกับส้อมและโคลน ฉันได้เห็นว่า:
fork เป็นกระบวนการและโคลนสำหรับเธรด
fork เพียงเรียกการโคลน clone ถูกใช้สำหรับกระบวนการและเธรดทั้งหมด
ถูกต้องหรือไม่ อะไรคือความแตกต่างระหว่าง 2 syscalls ที่มีเคอร์เนล 2.6 Linux?
คำตอบ:
fork()
เป็นการเรียกระบบ UNIX ดั้งเดิม สามารถใช้เพื่อสร้างกระบวนการใหม่ไม่ใช่เธรดเท่านั้น นอกจากนี้ยังพกพาได้
ใน Linux clone()
คือการเรียกใช้ระบบใหม่ที่หลากหลายซึ่งสามารถใช้เพื่อสร้างเธรดการทำงานใหม่ เธรดการเรียกใช้ใหม่สามารถยึดตามซีแมนทิกส์ของกระบวนการ UNIX, เธรด POSIX, สิ่งที่อยู่ระหว่างหรือสิ่งที่แตกต่างกันโดยสิ้นเชิงขึ้นอยู่กับตัวเลือกที่ส่งผ่าน คุณสามารถระบุตัวเลือกทุกประเภทที่กำหนดว่าหน่วยความจำตัวอธิบายไฟล์เนมสเปซต่างๆตัวจัดการสัญญาณและอื่น ๆ จะถูกแชร์หรือคัดลอก
เนื่องจากclone()
เป็นการเรียกใช้ระบบ superset การประยุกต์ใช้fork()
wrapper การเรียกใช้ระบบใน glibc จะเรียกจริงclone()
แต่นี่เป็นรายละเอียดการนำไปปฏิบัติที่โปรแกรมเมอร์ไม่จำเป็นต้องรู้ การfork()
เรียกใช้ระบบจริงที่แท้จริงยังคงมีอยู่ในเคอร์เนล Linux สำหรับเหตุผลด้านความเข้ากันได้แบบย้อนหลังแม้ว่าจะกลายเป็นสิ่งซ้ำซ้อนเนื่องจากโปรแกรมที่ใช้ libc เวอร์ชันเก่ามากหรือ libc อื่นนอกเหนือจาก glibc อาจใช้งานได้
clone()
ยังใช้เพื่อpthread_create()
สร้างฟังก์ชัน POSIX สำหรับสร้างเธรด
โปรแกรมแบบพกพาควรจะเรียกfork()
และไม่pthread_create()
clone()
ดูเหมือนว่ามีสองclone()
สิ่งที่ลอยอยู่ใน Linux 2.6
มีการโทรของระบบ:
int clone(int (*fn)(void *), void *child_stack,
int flags, void *arg, ...
/* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
นี่คือ "โคลน ()" man 2 clone
อธิบายโดยการทำ
หากคุณอ่าน man page นั้นใกล้พอคุณจะเห็นสิ่งนี้:
It is actually a library function layered on top of the
underlying clone() system call.
เห็นได้ชัดว่าคุณควรจะใช้เธรดโดยใช้ "ฟังก์ชั่นห้องสมุด" ในการเรียกระบบที่มีชื่อเหมือนกันอย่างสับสน
ฉันเขียนโปรแกรมสั้น ๆ :
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int
main(int ac, char **av)
{
pid_t cpid;
switch (cpid = fork()) {
case 0: // Child process
break;
case -1: // Error
break;
default: // parent process
break;
}
return 0;
}
คอมไพล์ด้วย: c99 -Wall -Wextra
และเรียกใช้งานภายใต้strace -f
เพื่อดูว่าระบบเรียกการฟอร์กทำอะไรได้บ้าง ฉันได้สิ่งนี้จากstrace
เครื่อง Linux 2.6.18 (x86_64 CPU):
20097 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x2b4ee9213770) = 20098
20097 exit_group(0) = ?
20098 exit_group(0)
ไม่มีการเรียก "fork" ปรากฏในstrace
เอาต์พุต การclone()
เรียกที่แสดงในstrace
เอาต์พุตมีอาร์กิวเมนต์ต่างกันมากจาก man-page-clone เป็นอาร์กิวเมนต์แรกจะแตกต่างกว่าchild_stack=0
int (*fn)(void *)
ปรากฏว่ามีการfork(2)
เรียกใช้ระบบในแง่ของจริง clone()
เช่นเดียวกับ "ฟังก์ชั่นห้องสมุด" clone()
มีการใช้งาน จริง clone()
มีชุดที่แตกต่างกันของการขัดแย้งจากคนหน้าโคลน
อย่างง่ายงบทั้งสองที่ขัดแย้งกันของคุณเกี่ยวกับfork()
และclone()
ถูกต้อง แม้ว่า "โคลน" ที่เกี่ยวข้องจะแตกต่างกัน
man 2 clone
วลีที่เป็นอย่างนั้นซึ่งฉันคิดว่ามันทำให้เกิดความสับสนและป้องกันไม่ให้ผู้ถามได้รับคำตอบที่ดี
clone
ฟังก์ชันไลบรารีแตกต่างจากรายการอาร์กิวเมนต์ที่ยอมรับโดยการเรียกระบบพื้นฐาน โดยเฉพาะการโทรระบบเสมอกลับสองครั้งในกองเดียวกันวิธีการแบบดั้งเดิมfork
ไม่; อาร์กิวเมนต์ทั้งหมดที่เกี่ยวข้องกับ child stack ได้รับการจัดการอย่างเคร่งครัดในพื้นที่ของผู้ใช้ ดูตัวอย่างsourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/…
fork()
clone()
เป็นเพียงชุดใดชุดหนึ่งของธงที่จะโทรระบบ clone()
เป็นเรื่องทั่วไปพอที่จะสร้าง "กระบวนการ" หรือ "เธรด" หรือแม้แต่สิ่งแปลก ๆ ที่อยู่ระหว่างกระบวนการและเธรด (ตัวอย่างเช่น "กระบวนการ" ที่แตกต่างกันซึ่งใช้ตารางตัวอธิบายไฟล์เดียวกัน)
เป็นหลักสำหรับทุก ๆ "ประเภท" ของข้อมูลที่เกี่ยวข้องกับบริบทการดำเนินการในเคอร์เนลclone()
ให้คุณเลือก aliasing ข้อมูลนั้นหรือคัดลอกมัน เธรดสอดคล้องกับนามแฝงกระบวนการสอดคล้องกับการคัดลอก ด้วยการระบุการรวมกันระหว่างสถานะของธงclone()
คุณสามารถสร้างสิ่งแปลก ๆ ที่ไม่ใช่กระทู้หรือกระบวนการ โดยปกติคุณไม่ควรทำเช่นนี้และฉันคิดว่ามีการถกเถียงกันบ้างในระหว่างการพัฒนาเคอร์เนล Linux เกี่ยวกับว่าควรอนุญาตให้มีกลไกทั่วไปเช่นclone()
นี้หรือไม่