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


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.