มีการใช้เธรดเป็นกระบวนการบน Linux หรือไม่


65

ฉันจะอ่านหนังสือเล่มนี้การเขียนโปรแกรม Linux ขั้นสูงโดย Mark Mitchell, Jeffrey Oldham และ Alex Samuel มันมาจากปี 2001 เก่าไปหน่อย แต่ฉันคิดว่ามันค่อนข้างดี แต่อย่างใด

อย่างไรก็ตามฉันมาถึงจุดที่มันแตกต่างจากสิ่งที่ Linux ของฉันผลิตในการส่งออกเปลือก บนหน้า 92 (116 ในตัวแสดง) บทที่ 4.5 การใช้งานเธรด GNU / Linux เริ่มต้นด้วยย่อหน้าที่มีคำสั่งนี้:

การติดตั้งเธรด POSIX บน GNU / Linux แตกต่างจากการใช้เธรดในระบบที่คล้ายกับ UNIX อื่น ๆ ในวิธีการที่สำคัญ: บน GNU / Linux เธรดจะถูกใช้เป็นกระบวนการ

ดูเหมือนว่าจะเป็นจุดสำคัญและจะแสดงในภายหลังด้วยรหัส C ผลลัพธ์ในหนังสือเล่มนี้คือ:

main thread pid is 14608
child thread pid is 14610

และใน Ubuntu 16.04 ของฉันมันคือ:

main thread pid is 3615
child thread pid is 3615

ps เอาท์พุทรองรับสิ่งนี้

ฉันคิดว่าบางสิ่งบางอย่างต้องเปลี่ยนไประหว่างปี 2001 และตอนนี้

หัวข้อย่อยถัดไปในหน้าถัดไป 4.5.1 การจัดการสัญญาณสร้างขึ้นบนคำสั่งก่อนหน้า:

พฤติกรรมของการมีปฏิสัมพันธ์ระหว่างสัญญาณและเธรดแตกต่างกันไปจากระบบที่เหมือน UNIX หนึ่งไปสู่อีกระบบหนึ่ง ใน GNU / Linux พฤติกรรมนั้นถูกกำหนดโดยความจริงที่ว่าเธรดถูกใช้เป็นกระบวนการ

และดูเหมือนว่าสิ่งนี้จะมีความสำคัญมากกว่าในภายหลังในหนังสือ มีคนอธิบายได้ไหมว่าเกิดอะไรขึ้นที่นี่

ฉันเคยเห็นอันนี้เคอร์เนล Linux มีกระบวนการเคอร์เนลจริง ๆ หรือไม่ แต่มันก็ไม่ได้ช่วยอะไรมาก ฉันสับสน

นี่คือรหัส C:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

void* thread_function (void* arg)
{
    fprintf (stderr, "child thread pid is %d\n", (int) getpid ());
    /* Spin forever. */
    while (1);
    return NULL;
}

int main ()
{
    pthread_t thread;
    fprintf (stderr, "main thread pid is %d\n", (int) getpid ());
    pthread_create (&thread, NULL, &thread_function, NULL);
    /* Spin forever. */
    while (1);
    return 0;
}

1
ฉันไม่เข้าใจว่าความสับสนของคุณคืออะไร เธรดถูกใช้เป็นกระบวนการที่แชร์พื้นที่แอดเดรสกับพาเรนต์
Johan Myréen

2
@ JohanMyréenแล้วทำไม pids ถึงเท่ากัน?
Tomasz

อาตอนนี้ฉันเห็นแล้ว ใช่มีบางอย่างเปลี่ยนแปลงไป ดูคำตอบของ @ ilkkachu
Johan Myréen

5
หัวข้อจะยังคงดำเนินการตามกระบวนการ - แต่ตอนนี้getpidผลตอบแทนสิ่งที่จะเรียกได้ว่าเป็นกลุ่ม ID ด้ายgettidและเพื่อให้ได้หมายเลขที่ไม่ซ้ำกันสำหรับกระบวนการที่คุณจำเป็นต้องใช้ อย่างไรก็ตามนอกเหนือจากเคอร์เนลคนและเครื่องมือส่วนใหญ่จะเรียกกระบวนการกลุ่มเธรดและเรียกกระบวนการเธรดสำหรับความสอดคล้องกับระบบอื่น ๆ
user253751

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

คำตอบ:


50

ฉันคิดว่าส่วนหนึ่งของclone(2)หน้าคนนี้อาจทำให้เข้าใจถึงความแตกต่างได้ PID:

CLONE_THREAD (ตั้งแต่ Linux 2.4.0-test8)
หากตั้งค่า CLONE_THREAD เด็กจะอยู่ในกลุ่มเธรดเดียวกับกระบวนการเรียก
กลุ่มเธรดเป็นคุณลักษณะที่เพิ่มใน Linux 2.4 เพื่อรองรับแนวคิด POSIX ของชุดเธรดที่แบ่งใช้ PID เดียว ภายใน PID ที่ใช้ร่วมกันนี้เป็นตัวระบุกลุ่มด้าย (TGID) สำหรับกลุ่มเธรด ตั้งแต่ Linux 2.4, การเรียกใช้เพื่อ getpid (2) คืนค่า TGID ของผู้เรียก

วลี "เธรดถูกใช้เป็นกระบวนการ" หมายถึงปัญหาของเธรดที่มี PID แยกต่างหากในอดีต โดยทั่วไปแล้ว Linux เดิมไม่มีเธรดภายในกระบวนการเพียงแยกกระบวนการ (ด้วย PID แยก) ที่อาจมีทรัพยากรที่ใช้ร่วมกันเช่นหน่วยความจำเสมือนหรือตัวอธิบายไฟล์ CLONE_THREADและการแยก process ID (*)และ thread ID ทำให้ลักษณะการทำงานของ Linux ดูเหมือนระบบอื่น ๆ และคล้ายกับข้อกำหนด POSIX ในแง่นี้ แม้ว่าในทางเทคนิคแล้วระบบปฏิบัติการจะยังไม่มีการใช้งานแยกกันสำหรับเธรดและกระบวนการ

การจัดการสัญญาณเป็นอีกหนึ่งพื้นที่ที่มีปัญหากับการดำเนินงานเก่านี้จะอธิบายในรายละเอียดมากขึ้นในกระดาษ @FooF หมายถึงในคำตอบของพวกเขา

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


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

@AndrewHenle ใช่แก้ไขนิดหน่อย ฉันหวังว่าจะรวบรวมความคิดของคุณแม้ว่าฉันจะลำบากกับถ้อยคำ (ไปข้างหน้าและแก้ไขส่วนนั้นหากคุณต้องการ) ฉันเข้าใจว่าระบบปฏิบัติการ Unix-like อื่น ๆ มีการแยกเธรดและกระบวนการต่างกันโดยที่ Linux เป็นข้อยกเว้นในการให้บริการประเภทเดียวเท่านั้น ฟังก์ชั่นทั้งสอง แต่ฉันไม่รู้เกี่ยวกับระบบอื่น ๆ และไม่มีแหล่งข้อมูลที่มีประโยชน์ดังนั้นจึงยากที่จะพูดอะไรที่เป็นรูปธรรม
ilkkachu

@tomas โปรดทราบว่าคำตอบนี้จะอธิบายวิธีการทำงานของ Linux ในขณะนี้ ตามคำแนะนำของ ilkkachu มันทำงานแตกต่างกันเมื่อเขียนหนังสือ คำตอบของ FooFอธิบายว่า Linux ทำงานอย่างไรในเวลานั้น
Gilles

38

คุณพูดถูก "สิ่งที่ต้องเปลี่ยนระหว่างปี 2001 ถึงตอนนี้" หนังสือที่คุณกำลังอ่านอธิบายโลกตามการใช้งานครั้งแรกของ POSIX เธรดบน Linux ที่เรียกว่าLinuxThreads (ดูบทความWikipediaสำหรับบางคน)

LinuxThreads มีปัญหาความเข้ากันได้กับมาตรฐาน POSIX ตัวอย่างเช่นเธรดที่ไม่แบ่งปัน PID และปัญหาร้ายแรงอื่น ๆ เพื่อแก้ไขข้อบกพร่องเหล่านี้การใช้งานอื่นที่เรียกว่า NPTL (Native POSIX เธรดไลบรารี) ได้รับการปรับปรุงโดย Red Hat เพื่อเพิ่มเคอร์เนลและไลบรารีพื้นที่ผู้ใช้ที่จำเป็นเพื่อรองรับการปฏิบัติตาม POSIX ได้ดีขึ้น (รับชิ้นส่วนที่ดีจากโครงการการปรับใช้ รุ่นต่อไปของ Posix Threads "), ดูWikipedia article บน NPTL ) แฟล็กเพิ่มเติมที่เพิ่มในการclone(2)เรียกระบบ (โดยเฉพาะอย่างยิ่งCLONE_THREADที่@ikkkachuชี้ให้เห็นในคำตอบของเขา ) น่าจะเป็นส่วนที่เห็นได้ชัดที่สุดของการปรับเปลี่ยนเคอร์เนล ส่วนพื้นที่ผู้ใช้ของงานในที่สุดก็รวมอยู่ใน GNU C Library

ยังคงเป็นปัจจุบันบาง SDK ของลินุกซ์ฝังตัวใช้การดำเนินการ LinuxThreads เก่าเพราะพวกเขาจะใช้หน่วยความจำรุ่นรอยขนาดเล็กของ libc เรียกว่าuClibc (เรียกว่าμClibc)และจะเอาจำนวนมากของปีก่อน NPTL การดำเนินงานพื้นที่ของผู้ใช้จาก GNU libc รังเพลิงและสันนิษฐานว่าเป็น การใช้เธรด POSIX เริ่มต้นโดยทั่วไปแล้วการพูดแพลตฟอร์มพิเศษเหล่านี้ไม่ได้มุ่งมั่นที่จะติดตามแฟชั่นล่าสุดด้วยความเร็วสูง สิ่งนี้สามารถสังเกตได้ด้วยการสังเกตว่า PID ที่แท้จริงสำหรับเธรดที่แตกต่างกันบนแพลตฟอร์มเหล่านั้นแตกต่างจากมาตรฐาน POSIX ที่ระบุเช่นเดียวกับหนังสือที่คุณกำลังอ่านอธิบาย จริงๆแล้วเมื่อคุณโทรมาpthread_create()ทันใดนั้นคุณก็เพิ่มจำนวนกระบวนการจากหนึ่งเป็นสามเนื่องจากกระบวนการเพิ่มเติมนั้นจำเป็นต้องทำให้เป็นระเบียบ

หน้าคู่มือLinux pthreads (7)ให้ภาพรวมที่ครอบคลุมและน่าสนใจของความแตกต่างระหว่างทั้งสอง อีกความกระจ่างแม้จะล้าสมัยคำอธิบายของความแตกต่างคือบทความนี้โดย Ulrich Depper และ Ingo Molnar เกี่ยวกับการออกแบบของ NPTL

ฉันขอแนะนำให้คุณอย่านำหนังสือเล่มนั้นไปใช้อย่างจริงจัง ฉันขอแนะนำเธรดการเขียนโปรแกรม POSIX เธรดและหน้าคู่มือ POSIX และ Linux ของ Butenhof แทนเกี่ยวกับเรื่องนี้ แบบฝึกหัดจำนวนมากในหัวข้อไม่ถูกต้อง


22

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

อย่างไรก็ตามเธรดเหล่านี้ถูกนำไปใช้เพื่อใช้ระบบบัญชีกระบวนการเคอร์เนลดังนั้นจึงได้รับการจัดสรร Thread ID ของตัวเอง (TID) แต่จะได้รับ PID เดียวกันและ 'กลุ่มกลุ่มเธรด ID' (TGID) เป็นกระบวนการหลัก - ซึ่งตรงกันข้ามกับ a fork ซึ่งมีการสร้าง TGID และ PID ใหม่และ TID เหมือนกับ PID

ดังนั้นปรากฏว่าเมล็ดที่ผ่านมามี TID แยกต่างหากที่สามารถสอบถามได้มันเป็นสิ่งที่แตกต่างกันสำหรับเธรดข้อมูลโค้ดที่เหมาะสมที่จะแสดงในแต่ละ main () thread_function () ด้านบนคือ:

    long tid = syscall(SYS_gettid);
    printf("%ld\n", tid);

ดังนั้นรหัสทั้งหมดนี้จะเป็น:

#include <pthread.h>                                                                                                                                          
#include <stdio.h>                                                                                                                                            
#include <unistd.h>                                                                                                                                           
#include <syscall.h>                                                                                                                                          

void* thread_function (void* arg)                                                                                                                             
{                                                                                                                                                             
    long tid = syscall(SYS_gettid);                                                                                                                           
    printf("child thread TID is %ld\n", tid);                                                                                                                 
    fprintf (stderr, "child thread pid is %d\n", (int) getpid ());                                                                                            
    /* Spin forever. */                                                                                                                                       
    while (1);                                                                                                                                                
    return NULL;                                                                                                                                              
}                                                                                                                                                             

int main ()                                                                                                                                                   
{                                                                                                                                               
    pthread_t thread;                                                                               
    long tid = syscall(SYS_gettid);     
    printf("main TID is %ld\n", tid);                                                                                             
    fprintf (stderr, "main thread pid is %d\n", (int) getpid ());                                                    
    pthread_create (&thread, NULL, &thread_function, NULL);                                           
    /* Spin forever. */                                                                                                                                       
    while (1);                                                                                                                                                
    return 0;                                                                                                                                                 
} 

ให้ตัวอย่างผลลัพธ์ของ:

main TID is 17963
main thread pid is 17963
thread TID is 17964
child thread pid is 17963

3
@tomas einonm ถูกต้อง ไม่สนใจสิ่งที่หนังสือพูดมันทำให้เกิดความสับสนอย่างมาก Dunno รู้ว่าความคิดที่ผู้เขียนต้องการสื่อ แต่เขาล้มเหลวอย่างรุนแรง ดังนั้นในลีนุกซ์คุณจะมี Kernel threads และ User-space threads เธรดเคอร์เนลเป็นกระบวนการที่สำคัญโดยไม่มีพื้นที่ผู้ใช้เลย เธรดพื้นที่ผู้ใช้เป็นเธรด POSIX ปกติ กระบวนการพื้นที่ผู้ใช้แชร์ไฟล์อธิบายสามารถแชร์เซ็กเมนต์รหัส แต่ใช้งานได้จริงในการแยกที่อยู่เสมือนอย่างสมบูรณ์ พื้นที่ผู้ใช้เธรดภายในส่วนรหัสที่ใช้ร่วมกันในกระบวนการหน่วยความจำแบบสแตติกและฮีป (หน่วยความจำแบบไดนามิก) แต่มีตัวประมวลผลแยกกันตั้งค่าชุดและสแต็ก
Boris Burkov

8

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

https://stackoverflow.com/questions/9154671/distinction-between-processes-and-threads-in-linux/9154725#9154725

Confusions เหล่านี้ล้วน แต่เกิดจากความจริงที่ว่าผู้พัฒนาเคอร์เนลมีมุมมองที่ไม่มีเหตุผลและไม่ถูกต้องที่เธรดสามารถนำไปใช้ได้เกือบทั้งหมดใน userspace โดยใช้กระบวนการเคอร์เนลเป็นแบบดั้งเดิมตราบใดที่เคอร์เนลเสนอวิธีที่จะทำให้พวกเขา . สิ่งนี้นำไปสู่การใช้งานเธรด Linux ที่ไม่ดีอย่างมากของเธรด POSIX ซึ่งค่อนข้างเป็นผู้เรียกชื่อผิดเนื่องจากมันไม่ได้ให้อะไรที่คล้ายกับโพสต์ความหมายของเธรด POSIX จากระยะไกล ในที่สุด LinuxThreads ถูกแทนที่ (โดย NPTL) แต่มีคำศัพท์ที่สับสนและความเข้าใจผิดจำนวนมาก

สิ่งแรกและสำคัญที่สุดที่ต้องตระหนักคือ "PID" หมายถึงสิ่งต่าง ๆ ในพื้นที่เคอร์เนลและพื้นที่ผู้ใช้ สิ่งที่เคอร์เนลเรียกว่า PIDs เป็น ID ระดับเคอร์เนลจริง ๆ (มักเรียกว่า TIDs) เพื่อไม่ให้สับสนpthread_tซึ่งเป็นตัวระบุแยกต่างหาก แต่ละเธรดบนระบบไม่ว่าจะในกระบวนการเดียวกันหรือต่างกันมี TID ที่ไม่ซ้ำกัน (หรือ "PID" ในคำศัพท์ของเคอร์เนล)

สิ่งที่ถือว่าเป็น PID ใน POSIX ในแง่ของ "กระบวนการ" ในทางตรงกันข้ามเรียกว่า "กลุ่มกลุ่มด้าย ID" หรือ "TGID" ในเคอร์เนล แต่ละกระบวนการประกอบด้วยหนึ่งหรือหลายเธรด (กระบวนการเคอร์เนล) แต่ละรายการด้วย TID ของตัวเอง (เคอร์เนล PID) แต่ทั้งหมดแชร์ TGID เดียวกันซึ่งเท่ากับ TID (เคอร์เนล PID) ของเธรดเริ่มต้นที่mainทำงาน

เมื่อtopแสดงเธรดให้คุณแสดงเป็น TID (เคอร์เนล PID) ไม่ใช่ PID (เคอร์เนล TGID) และนี่คือสาเหตุที่แต่ละเธรดมีเธรดแยกกัน

ด้วยการถือกำเนิดของ NPTL การเรียกใช้ระบบส่วนใหญ่ที่ใช้อาร์กิวเมนต์ PID หรือการดำเนินการกับกระบวนการที่เรียกได้เปลี่ยนไปเพื่อรักษา PID เป็น TGID และดำเนินการกับ "กลุ่มเธรด" ทั้งหมด (กระบวนการ POSIX)


8

ภายในไม่มีสิ่งเช่นกระบวนการหรือหัวข้อในเคอร์เนลลินุกซ์ กระบวนการและเธรดเป็นแนวคิดของ userland ส่วนใหญ่เคอร์เนลจะเห็นเฉพาะ "งาน" ซึ่งเป็นวัตถุที่กำหนดตารางเวลาได้ซึ่งอาจไม่มีทรัพยากรบางส่วนหรือทั้งหมดกับงานอื่น ๆ เธรดเป็นงานที่ได้รับการกำหนดค่าให้ใช้ทรัพยากรส่วนใหญ่ร่วมกัน (พื้นที่ที่อยู่, mmaps, ไพพ์, ตัวจัดการไฟล์เปิด, ซ็อกเก็ต ฯลฯ ) กับภารกิจหลักและกระบวนการเป็นงานที่ได้รับการกำหนดค่าให้ใช้ทรัพยากรน้อยที่สุดกับงานหลัก .

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

ในขณะที่ Linux 2.4 ใช้ TGID สิ่งนี้ส่วนใหญ่เป็นเพียงเพื่อประโยชน์ของการบัญชีทรัพยากร ผู้ใช้และเครื่องมือ userspace หลายคนพบว่ามีประโยชน์ที่จะสามารถจัดกลุ่มงานที่เกี่ยวข้องเข้าด้วยกันและรายงานการใช้ทรัพยากรร่วมกัน

การใช้งานใน Linux นั้นมีความคล่องตัวมากกว่ากระบวนการและเธรดโลกทัศน์ที่นำเสนอโดยเครื่องมือของผู้ใช้


กระดาษ @FooF อธิบายเชื่อมโยงกับจำนวนจุดที่เมล็ดมีการพิจารณากระบวนการและหัวข้อเป็นองค์กรที่แยกต่างหาก (เช่นการจัดการสัญญาณและ exec ()) ดังนั้นหลังจากที่ได้อ่านมันฉันไม่ได้จริงๆบอกว่า "ไม่มีเช่น สิ่งที่เป็นกระบวนการหรือหัวข้อในเคอร์เนลลินุกซ์ "
ilkkachu

5

Linus Torvalds ระบุไว้ในรายชื่อผู้รับจดหมายข่าวเคอร์เนลในปี 1996 ว่า "ทั้งเธรดและกระบวนการต่างๆได้รับการปฏิบัติในฐานะ" บริบทของการดำเนินการ "" ซึ่งก็คือ "เป็นเพียงการรวมตัวกันของทุกสถานะของ CoE นั้น ... สถานะ MMU สถานะการอนุญาตและสถานะการสื่อสารที่หลากหลาย (เปิดไฟล์ตัวจัดการสัญญาณ ฯลฯ ) "

// simple program to create threads that simply sleep
// compile in debian jessie with apt-get install build-essential
// and then g++ -O4 -Wall -std=c++0x -pthread threads2.cpp -o threads2
#include <string>
#include <iostream>
#include <thread>
#include <chrono>

// how many seconds will the threads sleep for?
#define SLEEPTIME 100
// how many threads should I start?
#define NUM_THREADS 25

using namespace std;

// The function we want to execute on the new thread.
void threadSleeper(int threadid){
    // output what number thread we've created
    cout << "task: " << threadid << "\n";
    // take a nap and sleep for a while
    std::this_thread::sleep_for(std::chrono::seconds(SLEEPTIME));
}

void main(){
    // create an array of thread handles
    thread threadArr[NUM_THREADS];
    for(int i=0;i<NUM_THREADS;i++){
        // spawn the threads
        threadArr[i]=thread(threadSleeper, i);
    }
    for(int i=0;i<NUM_THREADS;i++){
        // wait for the threads to finish
        threadArr[i].join();
    }
    // program done
    cout << "Done\n";
    return;
}

ในขณะที่คุณสามารถดูโปรแกรมนี้จะวางไข่ 25 เธรดในแต่ละครั้งแต่ละอันจะเข้าสู่โหมด 100 วินาทีจากนั้นเข้าร่วมโปรแกรมหลักอีกครั้ง หลังจากเธรดทั้งหมด 25 เธรดได้เข้าร่วมโปรแกรมอีกครั้งโปรแกรมจะเสร็จสิ้นและจะออกจากโปรแกรม

เมื่อใช้งานtopคุณจะสามารถดูโปรแกรม "threads2" ได้ 25 อินสแตนซ์ แต่น่าเบื่อนะ ผลลัพธ์ของps auwxมันน่าสนใจยิ่งกว่าเดิม ... แต่ps -eLfน่าตื่นเต้นมาก

UID        PID  PPID   LWP  C NLWP STIME TTY          TIME CMD
debian     689   687   689  0    1 14:52 ?        00:00:00 sshd: debian@pts/0  
debian     690   689   690  0    1 14:52 pts/0    00:00:00 -bash
debian    6217   690  6217  0    1 15:04 pts/0    00:00:00 screen
debian    6218  6217  6218  0    1 15:04 ?        00:00:00 SCREEN
debian    6219  6218  6219  0    1 15:04 pts/1    00:00:00 /bin/bash
debian    6226  6218  6226  0    1 15:04 pts/2    00:00:00 /bin/bash
debian    6232  6219  6232  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6233  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6234  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6235  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6236  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6237  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6238  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6239  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6240  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6241  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6242  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6243  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6244  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6245  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6246  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6247  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6248  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6249  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6250  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6251  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6252  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6253  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6254  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6255  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6256  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6232  6219  6257  0   26 15:04 pts/1    00:00:00 ./threads2
debian    6260  6226  6260  0    1 15:04 pts/2    00:00:00 ps -eLf

คุณสามารถดูได้ที่นี่ทั้ง 26 CoEs ที่thread2โปรแกรมได้สร้างขึ้น พวกเขาทั้งหมดใช้รหัสกระบวนการเดียวกัน (PID) และ ID กระบวนการหลัก (PPID) แต่แต่ละรหัส LWP ID (กระบวนการน้ำหนักเบา) แตกต่างกันและจำนวน LWPs (NLWP) แสดงว่ามี 26 CoEs - โปรแกรมหลักและ 25 กระทู้วางไข่โดยมัน


ถูกต้องเธรดเป็นเพียงกระบวนการที่มีน้ำหนักเบา (LWP)
fpmurphy

3

เมื่อมาถึงลินุกซ์กระบวนการและหัวข้อเป็นชนิดของสิ่งเดียวกัน ซึ่งก็คือพวกมันถูกสร้างขึ้นด้วยการเรียกระบบเดียวกัน: clone.

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

สิ่งที่ทำให้เธรดและวัตถุใกล้ชิดใน Linux คือการunshareเรียกระบบ วัตถุเคอร์เนลที่เริ่มต้นจากการแบ่งปันสามารถยกเลิกการแชร์หลังจากการสร้างเธรด ตัวอย่างเช่นคุณสามารถมีสองเธรดของกระบวนการเดียวกันซึ่งมีพื้นที่ตัวอธิบายไฟล์ต่างกัน (โดยการยกเลิกการแบ่งใช้ตัวอธิบายไฟล์หลังจากสร้างเธรดแล้ว) คุณสามารถทดสอบด้วยตนเองโดยการสร้างเธรดการโทรunshareทั้งสองเธรดแล้วปิดไฟล์ทั้งหมดและเปิดไฟล์ท่อหรือวัตถุใหม่ในทั้งสองเธรด จากนั้นดูใน/proc/your_proc_fd/task/*/fdและคุณจะเห็นว่าแต่ละคนtask(ซึ่งคุณสร้างเป็นเธรด) จะมี fd ที่แตกต่างกัน

ในความเป็นจริงการสร้างทั้งสองหัวข้อใหม่และกระบวนการใหม่ประจำห้องสมุดซึ่งเรียกcloneใต้และระบุว่าเคอร์เนลวัตถุที่สร้างขึ้นใหม่กระบวนการด้ายสิ่งเล็กสิ่งน้อย (เช่นtask) จะมีส่วนร่วมกับกระบวนการเรียกด้าย /

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