Giống như zombie thực sự, một quá trình zombie không thể bị giết, bởi vì nó đã chết.
Nó xảy ra như thế nào
Khi trong Linux / Unix, một tiến trình chết / kết thúc tất cả thông tin từ tiến trình sẽ bị xóa khỏi bộ nhớ hệ thống, chỉ còn lại mô tả quy trình. Quá trình nhận được ở trạng thái Z (zombie). Quá trình cha mẹ của anh ta nhận được tín hiệu từ kernel : SIGCHLD
, điều đó có nghĩa là một trong những tiến trình con của anh ta thoát ra, bị gián đoạn hoặc tiếp tục lại sau khi bị gián đoạn (trong trường hợp của chúng tôi đơn giản là nó thoát).
Bây giờ quy trình cha mẹ cần thực thi tòa nhà wait()
để đọc trạng thái thoát và thông tin khác từ quy trình con của mình. Sau đó, bộ mô tả được xóa khỏi bộ nhớ và quá trình không còn là zombie nữa.
Nếu tiến trình cha mẹ không bao giờ gọi tòa nhà wait()
, mô tả quá trình zombie ở lại trong bộ nhớ và ăn não. Thông thường bạn không thấy các quy trình zombie, vì quy trình trên mất ít thời gian hơn.
Bình minh của người chết
Mỗi mô tả quá trình cần một lượng bộ nhớ rất nhỏ, vì vậy một vài zombie không nguy hiểm lắm (như trong đời thực). Một vấn đề là mỗi quy trình zombie giữ id tiến trình của anh ta và hệ điều hành Linux / Unix có số lượng pid hạn chế. Nếu một phần mềm được lập trình không đúng cách tạo ra nhiều quy trình zombie, thì có thể xảy ra rằng các quy trình không thể được bắt đầu nữa vì không có thêm id quá trình nào khả dụng.
Vì vậy, nếu họ ở trong các nhóm lớn, họ rất nguy hiểm (như trong nhiều bộ phim được thể hiện rất tốt)
Làm thế nào chúng ta có thể tự bảo vệ mình trước một đám zombie?
Một phát súng vào đầu sẽ có tác dụng, nhưng tôi không biết lệnh cho điều đó (SIGKILL sẽ không hoạt động vì quá trình đã chết).
Chà, bạn có thể gửi SIGCHLD thông qua kill cho tiến trình cha, nhưng khi nó bỏ qua tín hiệu này thì sao? Tùy chọn duy nhất của bạn là tiêu diệt tiến trình cha mẹ và quá trình init "thông qua" zombie. Ban đầu, định kỳ gọi tòa nhà wait()
chọc trời để dọn dẹp lũ trẻ zombie của mình.
Trong trường hợp của bạn
Trong trường hợp của bạn, bạn phải gửi SIGCHLD cho quy trình crond:
root@host:~# strace -p $(pgrep cron)
Process 1180 attached - interrupt to quit
Sau đó từ một thiết bị đầu cuối khác:
root@host:~$ kill -17 $(pgrep cron)
Đầu ra là:
restart_syscall(<... resuming interrupted call ...>) = ? ERESTART_RESTARTBLOCK (To be restarted)
--- SIGCHLD (Child exited) @ 0 (0) ---
wait4(-1, 0x7fff51be39dc, WNOHANG, NULL) = -1 ECHILD (No child processes) <-- Here it happens
rt_sigreturn(0xffffffffffffffff) = -1 EINTR (Interrupted system call)
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=1892, ...}) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {0x403170, [CHLD], SA_RESTORER|SA_RESTART, 0x7fd6a7e9d4a0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({42, 0}, ^C <unfinished ...>
Process 1180 detached
Bạn thấy tòa nhà wait4()
trả về -1 ECHILD, có nghĩa là không có quá trình con nào ở đó. Vì vậy, kết luận là: cron phản ứng với tòa nhà SIGCHLD và không nên buộc ngày tận thế.