สัญญาณจะถูกละเว้น (หายไป)?


9

ฉันมีแอปพลิเคชันที่สื่อสารกับคนงานผ่านสัญญาณ (โดยเฉพาะ SIGUSR1 / SIGUSR2 / SIGSTOP)

ฉันสามารถวางใจได้หรือไม่ว่าสิ่งที่เกิดขึ้นทุกสัญญาณจะถูกส่งและประมวลผลโดยตัวจัดการ?

จะเกิดอะไรขึ้นหากมีการส่งสัญญาณเร็วกว่าที่เป็นไปไม่ได้สำหรับแอปพลิเคชันในการจัดการสัญญาณเหล่านั้น (เช่นเนื่องจากโหลดโฮสต์สูงในขณะนี้)

คำตอบ:


8

นอกเหนือจากปัญหา "สัญญาณมากเกินไป" สัญญาณสามารถถูกละเว้นอย่างชัดเจน จากman 2 signal:

If the signal signum is delivered to the process, then one of the
following happens:    
  *  If the disposition is set to SIG_IGN, then the signal is ignored.

สัญญาณสามารถถูกบล็อกได้ จากman 7 signal;

A signal may be blocked, which means that it will not be delivered
until it is later unblocked.  Between the time when it is generated
and when it is delivered a signal is said to be pending.

ทั้งชุดที่ถูกบล็อกและละเว้นถูกสืบทอดโดยกระบวนการลูกดังนั้นจึงอาจเกิดขึ้นได้ว่ากระบวนการหลักของแอปพลิเคชันของคุณเพิกเฉยหรือบล็อกสัญญาณใดสัญญาณหนึ่งเหล่านี้

จะเกิดอะไรขึ้นเมื่อมีการส่งสัญญาณหลายสัญญาณก่อนที่กระบวนการจะจัดการสัญญาณก่อนหน้าเสร็จสิ้น ขึ้นอยู่กับระบบปฏิบัติการ signal(2)manpage เชื่อมโยงดังกล่าวกล่าวถึงมัน

  • ระบบ V จะรีเซ็ตการจัดการสัญญาณเป็นค่าเริ่มต้น การส่งสัญญาณหลายอย่างรวดเร็วจะส่งผลให้เกิดการโทรซ้ำ (?)
  • BSD จะบล็อกสัญญาณโดยอัตโนมัติจนกว่าตัวจัดการจะเสร็จสิ้น
  • บน Linux สิ่งนี้ขึ้นอยู่กับการตั้งค่าสถานะการคอมไพล์สำหรับ GNU libcแต่ฉันคาดว่าพฤติกรรม BSD

4
หน้า man ของ Linux สำหรับsignal(2)แนะนำอย่างเด่นชัดว่าคุณหลีกเลี่ยงความสับสนนี้โดยใช้sigaction(2)แทน
Nate Eldredge

7

คุณไม่สามารถวางใจได้ว่าทุกสัญญาณที่ส่งจะถูกส่ง ตัวอย่างเช่นเคอร์เนล linux "รวมตัวกัน" SIGCHLDหากกระบวนการใช้เวลานานในการจัดการ SIGCHLD จากกระบวนการลูกที่ออก

ในการตอบคำถามอีกส่วนของคุณสัญญาณจะได้รับ "เข้าคิว" ภายในเคอร์เนลหากสัญญาณต่าง ๆ จำนวนหนึ่งเข้ามาสั้นเกินไปในช่วงเวลาหนึ่ง

คุณควรใช้sigaction()เพื่อตั้งค่าตัวจัดการสัญญาณด้วยsa_sigactionสมาชิกsiginfo_tตั้งค่าsa_maskสมาชิกของsiginfo_tอาร์กิวเมนต์อย่างระมัดระวัง ฉันคิดว่านี่หมายถึงปิดบังสัญญาณ "asynch" ทั้งหมดอย่างน้อย จากหน้า man สำหรับ Linux sigaction()คุณจะปกปิดสัญญาณที่กำลังจัดการอยู่ ฉันคิดว่าคุณควรตั้งค่าsa_flagsสมาชิกเป็น SA_SIGINFO แต่ฉันจำไม่ได้ว่าทำไมฉันถึงมีความเชื่อทางไสยศาสตร์ ฉันเชื่อว่าสิ่งนี้จะทำให้กระบวนการของคุณเป็นตัวจัดการสัญญาณที่ยังคงตั้งค่าโดยไม่มีเงื่อนไขการแข่งขันและสิ่งที่ไม่ได้ถูกขัดจังหวะโดยสัญญาณอื่น ๆ ส่วนใหญ่

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

นอกจากนี้คุณจะต้องทดสอบรหัสการจัดการสัญญาณของคุณอย่างละเอียดถี่ถ้วน วางไว้ในกระบวนการทดสอบขนาดเล็กและส่งสัญญาณ SIGUSR1 และ SIGUSR2 ให้ได้มากที่สุดอาจจะมาจากโปรแกรมส่งสัญญาณวัตถุประสงค์พิเศษ 2 หรือ 3 จุด ผสมสัญญาณอื่น ๆ เช่นกันหลังจากคุณมั่นใจว่ารหัสของคุณสามารถจัดการ SIGUSR1 และ SIGUSR2 ได้อย่างรวดเร็วและถูกต้อง เตรียมตัวสำหรับการดีบั๊กที่ยากลำบาก

หากคุณใช้ linux และ linux เท่านั้นคุณอาจคิดถึงการใช้signalfd()เพื่อสร้าง file descriptor ที่คุณสามารถselect()หรือโพลเพื่อรับสัญญาณเหล่านั้นได้ การใช้signalfd()อาจทำให้การดีบักง่ายขึ้น


2
ไม่ใช่แค่ SIGCLD ที่รวมตัวกัน: สัญญาณทั้งหมดอาจรวมตัวกันหากพวกมันถูกส่งก่อนที่จะประมวลผลได้
Gilles 'SO- หยุดความชั่วร้าย'

มีการวัดว่า "ยาวเกินไป" สำหรับสัญญาณ SIGCHLD หรือไม่? ฉันกำลังประสบกับพฤติกรรมนี้ในโปรแกรมของฉันในตอนนี้และตัวจัดการสัญญาณของฉันใช้เวลาไม่เกิน ~ 100ms ที่ฉันจะนับ
xrisk

@Rishav - สำหรับความรู้ของฉันไม่มีทางที่จะค้นหาว่า "ยาวเกินไป" คืออะไร ฉันคาดว่าการโหลดระบบโดยรวมเป็นสิ่งสำคัญ นั่นคือกระบวนการอื่น ๆ และเคอร์เนลที่ทำจะมีผลต่อ "ระยะเวลา" ระหว่างสัญญาณเพื่อให้พวกเขาได้รวมกัน ไม่ใช่คำตอบที่เป็นประโยชน์ฉันคิดว่า
Bruce Ediger

6

สัญญาณรับประกันว่าจะส่งมอบในแง่ที่ว่าหากกระบวนการเรียกสำเร็จ killจากนั้นเป้าหมายจะรับสัญญาณ นี่คืออะซิงโครนัส: ผู้ส่งไม่มีทางรู้ว่าเมื่อใดที่สัญญาณได้รับหรือประมวลผล อย่างไรก็ตามสิ่งนี้ไม่รับประกันว่าสัญญาณจะถูกส่ง เป้าหมายอาจตายก่อนที่จะสามารถประมวลผลสัญญาณได้ หากเป้าหมายไม่สนใจสัญญาณ ณ เวลาที่ส่งสัญญาณจะไม่มีผลใด ๆ หากเป้าหมายได้รับหลายอินสแตนซ์ของหมายเลขสัญญาณเดียวกันก่อนที่จะสามารถประมวลผลสัญญาณอาจรวมกัน (และมักจะ) รวมกัน: หากคุณส่งสัญญาณเดียวกันสองครั้งไปยังกระบวนการคุณไม่สามารถทราบได้ว่ากระบวนการจะรับสัญญาณหรือไม่ ครั้งเดียวหรือสองครั้ง. สัญญาณส่วนใหญ่ได้รับการออกแบบมาเพื่อฆ่ากระบวนการหรือเป็นวิธีที่จะทำให้กระบวนการใส่ใจพวกเขาไม่ได้ออกแบบมาเพื่อการสื่อสาร

หากคุณต้องการการจัดส่งที่เชื่อถือได้คุณต้องใช้กลไกการสื่อสารที่แตกต่างกัน มีสองกลไกการสื่อสารหลักระหว่างกระบวนการ: ไปป์ช่วยให้การสื่อสารทิศทางเดียว; ซ็อกเก็ตช่วยให้การสื่อสารแบบสองทิศทางและการเชื่อมต่อหลายไปยังเซิร์ฟเวอร์เดียวกัน หากคุณต้องการให้เป้าหมายประมวลผลการแจ้งเตือนได้มากเท่าที่คุณต้องการให้ส่งไบต์ไปตามไพพ์


4
คุณหมายถึงการเขียน "สัญญาณรับประกันว่าจะส่งมอบ" ตั้งแต่คุณอธิบายวิธีการบางอย่างที่สัญญาณจะไม่ถูกส่ง (เช่นกระบวนการเสียชีวิตก่อนที่จะได้รับหรือสัญญาณถูกรวมกัน)?
จอห์นนี่

2

เคอร์เนลมีอิสระในการรวมสัญญาณมาตรฐานหากมีมากกว่าหนึ่งสัญญาณถูกส่งในขณะที่ถูกบล็อก สัญญาณเรียลไทม์ในทางกลับกันจะไม่พิการในทำนองเดียวกัน

จากสัญญาณ (7) หน้าคู่มือ :

สัญญาณเรียลไทม์มีความแตกต่างดังต่อไปนี้:

  1. สัญญาณแบบเรียลไทม์หลายตัวสามารถจัดคิวได้ ในทางตรงกันข้ามหากมีการส่งสัญญาณมาตรฐานหลายอินสแตนซ์ในขณะที่สัญญาณนั้นถูกบล็อกอยู่ในขณะนั้นอินสแตนซ์เดียวเท่านั้นที่ถูกจัดคิว

ลองใช้สัญญาณที่มีตัวเลขอยู่ในช่วง SIGRTMIN ถึง SIGRTMAX


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