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ử
- Gửi
SIGTERMcho một chương trình từ một terminal khác và xem nó thoát sạch. - Dùng
kill(pid, 0)để kiểm tra một tiến trình còn sống không. - Bắt
SIGINT, hỏi xác nhận,Ctrl+Clần hai thì thoát ngay. - 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. - Bỏ qua
SIGPIPEvà chứng minh ghi vào ống đã đóng trảEPIPEthay vì giết chương trình. - Cài đồng hồ đếm ngược dùng
SIGALRMvà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
killgửi tín hiệu tới tiến trình khác,raisegử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
SIGINTvàSIGTERM, đặt cờ, dọn dẹp ở vòng lặp chính; không bắt đượcSIGKILL. - Thiết kế để ngay cả khi bị
SIGKILLhay mất điện dữ liệu vẫn không hỏng, bằng ghi tệp an toàn. - Bỏ qua
SIGPIPElà bắt buộc trong server mạng, nếu không một client có thể làm sập dịch vụ.