Bỏ qua điều hướng, tới nội dung chính
Học C
Bài 44.324 phút đọc

kill và thoát sạch

Sau bài này bạn sẽ làm được

  • Gửi tín hiệu bằng kill, raise, và kiểm tra tiến trình sống
  • Cài thoát sạch bắt SIGINT và SIGTERM
  • Bỏ qua SIGPIPE cho chương trình mạng
  • Dọn dẹp tài nguyên ở vòng lặp chính, không ở handler

Tín hiệu không chỉ để nhận, mà còn để gửi. kill gửi một tín hiệu tới tiến trình khác. Ghép với việc bắt tín hiệu, bạn có thoát sạch: một chương trình dừng đúng lúc, dọn dẹp tài nguyên, và không mất dữ liệu.

#kill và raise

Gửi tín hiệu
#include <signal.h>

kill(pid, SIGTERM);        /* gui SIGTERM toi tien trinh pid */
kill(0, SIGTERM);          /* gui toi ca NHOM tien trinh cua minh */
kill(-pgid, SIGTERM);      /* gui toi nhom tien trinh pgid */
raise(SIGINT);             /* gui cho CHINH MINH, = kill(getpid(), SIGINT) */
terminal
# Cong cu dong lenh gui tin hieu
kill -l | head -3
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL
 5) SIGTRAP	 6) SIGABRT	 7) SIGBUS	 8) SIGFPE
 9) SIGKILL	10) SIGUSR1	11) SIGSEGV	12) SIGUSR2
kill -TERM 1234
# SIGKILL: bien phap cuoi cung
kill -9 1234
pkill -f mau_ten_chuong_trinh

#Kiểm tra tiến trình sống

#Thoát sạch

Graceful shutdown, mẫu chuẩn cho server
#include <signal.h>
#include <string.h>

static volatile sig_atomic_t nen_thoat = 0;
static void yeu_cau_thoat(int s) { (void)s; nen_thoat = 1; }

int main(void) {
    struct sigaction sa;
    memset(&sa, 0, sizeof sa);
    sa.sa_handler = yeu_cau_thoat;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    sigaction(SIGINT,  &sa, NULL);      /* Ctrl+C */
    sigaction(SIGTERM, &sa, NULL);      /* kill mac dinh, va khi tat may */

    /* Bo qua SIGPIPE: quan trong cho server mang */
    signal(SIGPIPE, SIG_IGN);

    while (!nen_thoat) {
        xu_ly_ket_noi();
    }

    /* Don dep TU TE o day, noi moi ham deu an toan */
    dong_moi_ket_noi();
    luu_du_lieu();
    giai_phong_bo_nho();
    return 0;
}
Không bắt tín hiệu
while (1) { xu_ly_ket_noi(); } /* Ctrl+C hoac kill giet ngay giua chung. Ket noi dang mo bi cat dot ngot, du lieu chua luu bi mat, tep dang ghi bi hong. */
Thoát sạch
sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); while (!nen_thoat) { xu_ly_ket_noi(); } dong_moi_ket_noi(); /* client biet server dong, khong dut dot ngot */ luu_du_lieu(); /* du lieu duoc luu truoc khi thoat */ /* Thoat co kiem soat, khong mat gi. */

#Bỏ qua SIGPIPE

Tự làm thử

  1. Gửi SIGTERM cho một chương trình từ một terminal khác và xem nó thoát sạch.
  2. Dùng kill(pid, 0) để kiểm tra một tiến trình còn sống không.
  3. Bắt SIGINT, hỏi xác nhận, Ctrl+C lần hai thì thoát ngay.
  4. Viết một server nhỏ thoát sạch: đóng kết nối và lưu dữ liệu khi nhận SIGTERM.
  5. Bỏ qua SIGPIPE và chứng minh ghi vào ống đã đóng trả EPIPE thay vì giết chương trình.
  6. Cài đồng hồ đếm ngược dùng SIGALRM và alarm.

Trình chấm điểm tự động sẽ được bổ sung ở giai đoạn sau. Hiện tại bạn tự chạy thử trên máy.

Tóm tắt

  • kill gửi tín hiệu tới tiến trình khác, raise gửi cho chính mình; tên hoặc số đều được.
  • kill(pid, 0) không gửi gì, chỉ kiểm tra tiến trình còn sống và bạn có quyền; cẩn thận đua PID.
  • Thoát sạch: bắt SIGINT và SIGTERM, đặt cờ, dọn dẹp ở vòng lặp chính; không bắt được SIGKILL.
  • Thiết kế để ngay cả khi bị SIGKILL hay mất điện dữ liệu vẫn không hỏng, bằng ghi tệp an toàn.
  • Bỏ qua SIGPIPE là bắt buộc trong server mạng, nếu không một client có thể làm sập dịch vụ.