ทำไม Ctrl-C ไม่ทำงาน


9

ฉันแค่กดCtrlcสองครั้งที่กระสุนของฉันเพื่อหยุดกระบวนการที่ใช้เวลานานกว่าจะเสร็จ

^C ถูกสะท้อนสองครั้ง แต่กระบวนการก็ยังดำเนินต่อไป

ทำไมไม่Ctrlcออกจากกระบวนการเหมือนปกติ


4
โซลูชันของฉันสำหรับโปรแกรมที่น่ารำคาญที่ไม่ต้องการตายมักจะระงับพวกเขาด้วย CTRL + Z kill -9 %เพื่อฆ่ามัน สัญญาณที่ 9 ไม่สามารถเพิกเฉยได้และไม่สามารถระงับสัญญาณได้ ลำดับของแป้นพิมพ์ CTRL + Z สามารถละเว้นได้ในทางทฤษฎี แต่ไม่สามารถใช้งานได้จริง
David Sainty

@DavidSainty สามารถระงับสัญญาณ suspend ได้ (หรืออย่างน้อยก็ไม่หยุด) ตัวอย่าง: perl -E '$SIG{TSTP} = sub { say "ha ha" }; sleep 1 while 1'. คุณอาจคิดถึง SIGSTOP ซึ่งเป็นสัญญาณที่แตกต่างกัน
Derobert

อ๊ะใช่แล้วคุณล่ะ :)
David Sainty

คำตอบ:


13

กระบวนการสามารถเลือก:

  • ไม่สนใจสัญญาณ SIGINT ที่มักจะส่งเมื่อกดCtrl-C(เช่นเดียวกับtrap '' INTในเชลล์) หรือมีตัวจัดการของมันเองซึ่งจะไม่ตัดสินใจยุติ (หรือล้มเหลวในการยุติในเวลาที่เหมาะสม)
  • บอกอุปกรณ์ปลายทางว่าตัวอักษรที่ทำให้ SIGINT ถูกส่งไปยังงานเบื้องหน้าเป็นอย่างอื่น (เช่นstty int '^K'ในเชลล์)
  • บอกให้เครื่องปลายทางไม่ส่งสัญญาณใด ๆ (เหมือนstty -isigในเปลือก)

หรือพวกเขาสามารถ uninterruptible เช่นเมื่ออยู่ในช่วงกลางของการเรียกระบบที่ไม่สามารถถูกขัดจังหวะ

บน Linux (ที่มีเคอร์เนลค่อนข้างล่าสุด) คุณสามารถบอกได้ว่ากระบวนการกำลังเพิกเฉยและ / หรือจัดการ SIGINT โดยดูที่ผลลัพธ์ของ

$ kill -l INT
2
$ grep Sig "/proc/$pid/status"
SigQ:   0/63858
SigPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000002
SigCgt: 0000000000000000

SIGINT คือ 2 บิตที่สองของ SigIgn ด้านบนคือ 1 ซึ่งหมายความว่า SIGINT จะถูกละเว้น

คุณสามารถทำให้เป็นอัตโนมัติด้วย:

$ SIG=$(kill -l INT) perl -lane 'print $1 if $F[0] =~ /^Sig(...):/ && 
    $F[1] & (1<<($ENV{SIG}-1))' < "/proc/$pid/status"
Ign

วิธีตรวจสอบintrอักขระปัจจุบันคืออะไรหรือหากisigเปิดใช้งานเทอร์มินัลที่กำหนด:

$ stty -a < /dev/pts/0
[...] intr = ^C [...] isig

(เหนือintrตัวละครคือ^C(ตัวละครมักส่งโดยเทอร์มินัลของคุณ (อีมูเลเตอร์) เมื่อกดCTRL-Cและสัญญาณอินพุตจะไม่ถูกปิดใช้งาน

$ stty -a < /dev/pts/1
[...] intr = ^K [...] -isig

( intrตัวละครเป็น^Kและisigถูกปิดการใช้งานสำหรับ/dev/pts/1)

เพื่อความสมบูรณ์มีสองวิธีที่กระบวนการอาจทำบางสิ่งเพื่อหยุดรับ SIGINT แม้ว่าจะไม่ใช่สิ่งที่คุณมักจะเห็น

เมื่อCtrl+Cสัญญาณ SIGINT ถูกส่งไปยังกระบวนการทั้งหมดในกลุ่มกระบวนการเบื้องหน้าของอาคาร มันมักจะเป็นเปลือกว่ากระบวนการที่เกิดขึ้นในกระบวนการกลุ่ม (แมปไปยังเปลือกงาน ) และบอกอุปกรณ์ปลายทางซึ่งเป็นเบื้องหน้าหนึ่ง

ตอนนี้กระบวนการสามารถ:

  • ออกจากกลุ่มกระบวนการ หากมันย้ายไปยังกลุ่มกระบวนการอื่น (กลุ่มกระบวนการใด ๆ แต่กลุ่มที่เป็นส่วนหน้า ) ก็จะไม่ได้รับ SIGINT เมื่อCtrl-C(หรือสัญญาณอื่น ๆ ที่เกี่ยวข้องกับคีย์บอร์ดเช่น SIGTSTP, SIGQUIT) อย่างไรก็ตามอาจถูกระงับหากพยายามอ่าน (อาจเขียนได้เช่นกันขึ้นอยู่กับการตั้งค่าอุปกรณ์เทอร์มินัล) จากอุปกรณ์เทอร์มินัล (ตามกระบวนการพื้นหลัง)

    ตัวอย่างเช่น:

    perl -MPOSIX -e 'setpgid(0,getppid) or die "$!"; sleep 10'

    ไม่อาจจะ Interruptible Ctrl-Cกับ ด้านบนperlจะพยายามเข้าร่วมกลุ่มกระบวนการที่มี ID เหมือนกับ ID กระบวนการหลัก โดยทั่วไปไม่รับประกันว่าจะมีกลุ่มกระบวนการที่มีรหัสนั้น แต่ที่นี่ในกรณีที่perlคำสั่งนั้นรันด้วยตัวเองที่พร้อมต์ของเชลล์แบบโต้ตอบ ppid จะเป็นกระบวนการของเชลล์และโดยทั่วไปเชลล์จะเริ่มต้นในกลุ่มกระบวนการของตัวเอง

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

    ยกตัวอย่างเช่นขึ้นอยู่กับเปลือก

    $ ps -j >&2 | perl -MPOSIX -e 'setpgid(0,0) or die "$!"; sleep 10'
      PID  PGID   SID TTY          TIME CMD
    21435 21435 21435 pts/12   00:00:00 zsh
    21441 21441 21435 pts/12   00:00:00 ps
    21442 21441 21435 pts/12   00:00:00 perl

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

  • หรืออาจเปลี่ยนกลุ่มกระบวนการพื้นหน้า บอกอุปกรณ์ tty โดยทั่วไปให้ส่ง SIGINT ไปยังกลุ่มกระบวนการอื่น ๆCtrl+C

    perl -MPOSIX -e 'tcsetpgrp (0, getppid) หรือตาย $ !; หลับ 5 '

    ที่นั่นperlยังคงอยู่ในกลุ่มกระบวนการเดียวกัน แต่บอกอุปกรณ์เทอร์มินัลว่ากลุ่มกระบวนการพื้นหน้าเป็นอุปกรณ์ที่มี ID เหมือนกับ ID กระบวนการหลัก (ดูหมายเหตุด้านบนเกี่ยวกับเรื่องนั้น)


1
ตัวอย่างที่ดีของการโทรติดต่อคือการเข้าถึงอุปกรณ์ฮาร์ดแวร์ที่ไม่ตอบสนอง ตัวอย่างเช่นหากคุณพยายามใช้hdparmหรือsmartctlบนฮาร์ดดิสก์ที่มีข้อบกพร่องซึ่งไม่ตอบสนองจะหยุดทำงานตลอดไปและคุณไม่สามารถฆ่าด้วย CTRL + C คุณสามารถบอกได้ว่าโปรเซสนั้นอยู่ในโหมดสเตนเลสที่ไม่สามารถขัดจังหวะได้หรือไม่โดยดูที่คอลัมน์สถิติของps auxหรือที่คอลัมน์ S ของtop/ htop- Dหมายถึงสลีพที่ทำงานแบบต่อเนื่องไม่ได้ นี่ไม่จำเป็นต้องเป็นสิ่งที่ไม่ดี แต่มันอาจหมายถึงว่ากระบวนการกำลังทำ IO มากมาย
Martin von Wittich
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.