ทำไมซอมบี้จึงกำลังรอลูกอยู่


11

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

$ cat <( sleep 100 & wait ) &
[1] 14247
$ ps ax -O pgid | grep $$
12126 12126 S pts/17   00:00:00 bash
14248 12126 S pts/17   00:00:00 bash
14249 12126 S pts/17   00:00:00 sleep 100
14251 14250 S pts/17   00:00:00 grep --color=auto 12126
$ kill -2 14248

$ ps ax -O pgid | grep $$
12126 12126 S pts/17   00:00:00 bash
14248 12126 Z pts/17   00:00:00 [bash] <defunct>
14249 12126 S pts/17   00:00:00 sleep 100
14255 14254 S pts/17   00:00:00 grep --color=auto 12126

ทำไมซอมบี้ถึงกำลังรอเด็กอยู่?

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

GNU ทุบตีรุ่น 4.3.42 (1) - ปล่อย (x86_64-pc-linux-gnu)

Linux 4.4.0-31-generic # 50-Ubuntu SMP พุธ 13 ก.ค. 00:07:12 UTC 2016 x86_64 x86_64 x86_64 GNU / Linux


2
ควรทราบว่าสิ่งนี้ไม่มีส่วนเกี่ยวข้องกับ bash (นอกเหนือจากข้อเท็จจริงที่ว่าถ้าคุณเลือกที่จะใช้ bash เป็นเชลล์ของคุณกระบวนการจำนวนมากจะเริ่มต้นโดย) เชลล์อื่น ๆ (tcsh, ksh, zsh, & c) ทุกกระบวนการเริ่มต้นและเรียกใช้ฟังก์ชั่นระบบปฏิบัติการเดียวกันเพื่อจัดการกับพวกเขา
— jamesqf

@jamesqf น่าสนใจ หากคุณต้องการที่จะขยายความคิดเห็นของคุณเป็นคำตอบเต็มเปี่ยมนั่นก็ดี

1
ยกเว้นว่ามันไม่ใช่คำตอบจริงๆเพียงแค่ชี้ให้เห็นว่าคุณกำลังมองหาคำตอบในสถานที่ที่ไม่ถูกต้อง :-) หนังสือดี ๆ เกี่ยวกับการเขียนโปรแกรมระบบ * nix ควรให้คำตอบที่ดีกว่าที่ฉันเขียนได้
— jamesqf

คำตอบ:


17

ซอมบี้ไม่รอลูกของมัน เช่นเดียวกับกระบวนการซอมบี้ใด ๆ มันจะอยู่รอบ ๆ จนกว่าผู้ปกครองจะรวบรวมมัน

คุณควรแสดงกระบวนการทั้งหมดที่เกี่ยวข้องเพื่อทำความเข้าใจว่าเกิดอะไรขึ้นและดู PPID ด้วย ใช้บรรทัดคำสั่งนี้:

ps -t $(tty) -O ppid,pgid

catผู้ปกครองของกระบวนการที่คุณกำลังฆ่าคือ สิ่งที่เกิดขึ้นคือ bash นั้นรันคำสั่ง background cat <( sleep 100 & wait )ใน subshell เนื่องจากสิ่งเดียวที่ subshell นี้ทำคือการตั้งค่าการเปลี่ยนเส้นทางบางส่วนจากนั้นเรียกใช้คำสั่งภายนอกดังนั้น subshell นี้จึงถูกแทนที่ด้วยคำสั่งภายนอก นี่คือบทสรุป:

  • การทุบตีดั้งเดิม (12126) การเรียกforkเพื่อดำเนินการคำสั่งพื้นหลังcat <( sleep 100 & wait )ในเด็ก (14247)
    • เด็ก (14,247) เรียกร้องpipeในการสร้างท่อแล้วในการสร้างเด็กที่จะเรียกใช้ทดแทนกระบวนการ forksleep 100 & wait
      • หลาน (14248) เรียกforkให้ทำงานsleep 100ในพื้นหลัง เนื่องจากหลานไม่ได้มีการโต้ตอบกระบวนการพื้นหลังจึงไม่ทำงานในกลุ่มกระบวนการแยกต่างหาก จากนั้นหลานสาวก็รอที่sleepจะออก
    • เด็ก (14247) โทรsetpgid(มันเป็นงานพื้นหลังในเปลือกโต้ตอบจึงได้รับกลุ่มกระบวนการของตัวเอง) จากนั้นจะวิ่งexecve cat(ฉันประหลาดใจเล็กน้อยที่การแทนที่กระบวนการไม่ได้เกิดขึ้นในกลุ่มกระบวนการพื้นหลัง)
  • คุณฆ่าหลาน (14248) แม่กำลังทำงานcatซึ่งรู้อะไรเกี่ยวกับขั้นตอนเด็ก ๆ waitและมีการโทรทางธุรกิจ เนื่องจากพ่อแม่ของหลานไม่ได้เก็บกินหลานก็อยู่ข้างหลังเหมือนเป็นซอมบี้
  • ในที่สุดcatออกจาก - เพราะคุณฆ่ามันหรือเพราะsleepผลตอบแทนและปิดไปป์ดังนั้นcatจะเห็นจุดสิ้นสุดของอินพุต ณ จุดนั้นผู้ปกครองของซอมบี้ตายดังนั้นซอมบี้จะถูกรวบรวมโดย init และ init จะได้รับการรวบรวมใหม่

หากคุณเปลี่ยนคำสั่งเป็น

{ cat <( sleep 100 & wait ); echo done; } &

จากนั้นcatรันในกระบวนการแยกต่างหากไม่ใช่ในลูกของกระบวนการทุบตีดั้งเดิม: เด็กคนแรกต้องอยู่ข้างหลังเพื่อให้ทำงานecho doneได้ ในกรณีนี้ถ้าคุณฆ่าหลานมันไม่ได้อยู่ในฐานะซอมบี้เพราะเด็ก (ซึ่งยังคงกำลังทุบตี ณ จุดนั้นอยู่) จะทำการเก็บเกี่ยวใหม่

ดูเพิ่มเติมที่linux จัดการกระบวนการซอมบี้อย่างไรและซอมบี้สามารถมีเด็กกำพร้าได้อย่างไร เด็กกำพร้าจะถูกรบกวนจากการเก็บซอมบี้หรือไม่?


ฉันรู้สึกประหลาดใจกับสิ่งที่กลุ่มกระบวนการเช่นกัน ดูเหมือนว่ามันเป็นข้อบกพร่องและตอนนี้ได้รับการแก้ไขในสาขาทุบตี
— PSkocik

"bash ดั้งเดิมรอลูกของมัน (14247)" ทำไมหรือในทางใด เด็กควรจะทำงานในพื้นหลังและไม่มีการโทรที่ชัดเจน อะไรคือความแตกต่างระหว่าง bash ดั้งเดิม (14246) ที่รอ 14247 และ 14247 (ซึ่งกำลังรันอยู่cat) ที่ไม่รอ 14248 (กำลังรอsleep) มีความทรงจำบางอย่างของผู้ที่รอคอยซึ่งเด็ก (14247) หายไปและทุบตีดั้งเดิม (14246) ไม่ได้หรืออาจเป็นรายการของสัญญาณเช่น SIGCHLD ที่ควรจะเรียกและ 14247 (ตอนนี้ทำงานbash) ยกเลิกการสมัครด้วย เกี่ยวกับ 14248?

1
@ โทมัสฉันหมายถึงการทุบตีดั้งเดิมเรียกร้องwaitลูกของมัน ฉันสามารถดูว่าสิ่งนี้จะทำให้เกิดความสับสนฉันได้ลบประโยคที่ไม่ได้พูดถูกตามลำดับเวลา ข้อมูลที่กระบวนการตายไปแล้วไปยังผู้ปกครองของกระบวนการนั้นกระบวนการไม่สามารถ“ สมัครรับข้อมูล” เพื่อรับข้อมูลเกี่ยวกับการเสียชีวิตของกระบวนการอื่น
— Gilles 'หยุดความชั่วร้าย' ใน

6

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

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

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