C Academy · บทเรียน

สัญญาณ

การแจ้งเตือนแบบอะซิงโครนัส

บทเรียน 4 จาก 413 ขั้นตอน

สัญญาณ เป็นบทเรียน C Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน

สัญญาณคืออะไร

สัญญาณคือการแจ้งเตือนแบบอะซิงโครนัสที่ส่งไปยังกระบวนการเพื่อบอกว่าเกิดเหตุการณ์ขึ้น เช่น ผู้ใช้กด Ctrl-C หรือกระบวนการลูกสิ้นสุด สัญญาณเป็นรูปแบบ IPC ที่ใช้ทรัพยากรน้อย

สัญญาณทั่วไป

สัญญาณบางรายการที่คุณจะพบเป็นประจำ:

  • SIGINT การขัดจังหวะ (Ctrl-C)
  • SIGTERM คำขอให้ยุติการทำงานอย่างสุภาพ
  • SIGKILL การบังคับยุติ (ไม่สามารถดักจับได้)
  • SIGCHLD กระบวนการลูกเปลี่ยนสถานะ
  • SIGSEGV การเข้าถึงหน่วยความจำที่ไม่ถูกต้อง

การจัดการเริ่มต้น

สัญญาณแต่ละตัวมีการดำเนินการเริ่มต้น ได้แก่ ยุติการทำงาน, ยุติการทำงานพร้อมสร้าง core dump, เพิกเฉย, หยุด หรือ ทำงานต่อ คุณสามารถแทนที่การดำเนินการส่วนใหญ่ได้ด้วย handler

การติดตั้ง Handler

วิธีสมัยใหม่ที่ใช้ได้กับหลายแพลตฟอร์มในการกำหนด handler คือ sigaction โดย handler เป็นฟังก์ชันที่รับหมายเลขสัญญาณ

#include <signal.h>
#include <stdio.h>

void on_signal(int sig) {
    /* note: printf is not async-signal-safe; for demo only */
    write(1, "caught\n", 7);
}

int install(void) {
    struct sigaction sa = {0};
    sa.sa_handler = on_signal;
    return sigaction(SIGINT, &sa, NULL);
}

เหตุใดจึงไม่ใช้ signal()

ฟังก์ชันเก่าอย่าง signal() มีพฤติกรรมไม่สอดคล้องกันในแต่ละระบบ (handler ถูกตั้งค่าใหม่ และไม่มีตัวควบคุม SA_RESTART) ขอแนะนำให้ใช้ sigaction ซึ่งมีข้อกำหนดชัดเจนและใช้ได้กับหลายแพลตฟอร์ม

ฟังก์ชันที่ปลอดภัยต่อสัญญาณแบบอะซิงโครนัส

handler อาจขัดจังหวะโค้ดของคุณได้ทุกจุด ดังนั้นจึงเรียกใช้ได้เฉพาะฟังก์ชันที่ ปลอดภัยต่อสัญญาณแบบอะซิงโครนัส เช่น write การเรียก printf หรือ malloc จาก handler อาจทำให้เกิดการหยุดรอแบบ deadlock หรือข้อมูลเสียหาย

การใช้แฟล็ก volatile

รูปแบบที่ปลอดภัยคือ ให้ handler ตั้งค่าแฟล็ก volatile sig_atomic_t แล้วให้ลูปหลักตรวจสอบแฟล็กนั้น วิธีนี้ทำให้ handler มีขนาดเล็กและปลอดภัย

#include <signal.h>

volatile sig_atomic_t stop = 0;

void handler(int sig) {
    stop = 1; /* only set a flag */
}
/* main loop: while (!stop) { do_work(); } */

การส่งสัญญาณ

ใช้ kill(pid, sig) เพื่อส่งสัญญาณไปยังกระบวนการอื่น หรือใช้ raise(sig) เพื่อส่งสัญญาณให้ตัวเอง แม้ชื่อจะเป็น kill แต่ฟังก์ชันนี้ส่งสัญญาณได้ทุกชนิด ไม่ใช่เฉพาะสัญญาณที่ทำให้ถึงแก่การทำงานเท่านั้น

#include <signal.h>

int notify(int pid) {
    return kill(pid, SIGTERM); /* ask process to terminate */
}

การบล็อกสัญญาณ

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

#include <signal.h>

void block_int(void) {
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    sigprocmask(SIG_BLOCK, &set, NULL);
}

การเก็บกวาดกระบวนการลูกด้วย SIGCHLD

เมื่อกระบวนการลูกสิ้นสุดลง เคอร์เนลจะส่ง SIGCHLD handler ที่เรียก waitpid จะเก็บกวาดกระบวนการลูก ป้องกันไม่ให้เกิดกระบวนการ ซอมบี้ ที่ค้างอยู่ในตารางกระบวนการ

#include <signal.h>
#include <sys/wait.h>

void reap(int sig) {
    while (waitpid(-1, NULL, WNOHANG) > 0)
        ; /* reap all finished children */
}

สัญญาณที่ดักจับไม่ได้

มีสัญญาณสองตัวที่ไม่อาจเปลี่ยนแปลงได้: SIGKILL จะยุติการทำงานเสมอ และ SIGSTOP จะหยุดกระบวนการเสมอ สัญญาณเหล่านี้ไม่สามารถดักจับ บล็อก หรือเพิกเฉยได้ จึงทำให้ระบบมีวิธีควบคุมกระบวนการที่รับประกันได้

ตรวจสอบความเข้าใจ

ทดสอบความเข้าใจเกี่ยวกับสัญญาณของคุณ

สรุปทบทวน

คุณได้เรียนรู้เกี่ยวกับสัญญาณสำหรับการแจ้งเตือนแบบอะซิงโครนัส

  • ติดตั้ง handler ด้วย sigaction แทน signal แบบเก่า
  • handler ต้องใช้ฟังก์ชันที่ปลอดภัยต่อสัญญาณแบบอะซิงโครนัส ขอแนะนำให้ตั้งค่าแฟล็ก
  • ส่งสัญญาณด้วย kill/raise และบล็อกด้วย sigprocmask
  • เก็บกวาดกระบวนการลูกเมื่อได้รับ SIGCHLD ส่วน SIGKILL และ SIGSTOP ไม่สามารถดักจับได้
เริ่มต้นได้ฟรี

เรียนรู้ C ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
39
บทเรียน
144

คำถามที่พบบ่อย

บทเรียน “สัญญาณ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “สัญญาณ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “สัญญาณ”

การแจ้งเตือนแบบอะซิงโครนัส คุณปฏิบัติ C Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “สัญญาณ” ใช้เวลานานแค่ไหน

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

ฉันเขียนและรันโค้ดในบทเรียน C Academy นี้ได้ไหม

ได้ บทเรียน C Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ไปป์
  2. หน่วยความจำร่วม
  3. คิวข้อความ
  4. สัญญาณ
← กลับไปที่ C Academy