Các hệ thống UNIX/Linux cung cấp các cơ chế đặc biệt để giao tiếp giữa từng tiến trình riêng lẻ. Một trong những cơ chế này là các tín hiệu, và thuộc về các phương thức giao tiếp khác nhau giữa các tiến trình [Inter Process Communication, viết tắt là IPC]
Nói tóm lại, tín hiệu là các ngắt phần mềm được gửi đến chương trình [hoặc quy trình] để thông báo cho chương trình về các sự kiện hoặc yêu cầu quan trọng đối với chương trình để chạy một chuỗi mã đặc biệt. Một chương trình nhận được tín hiệu sẽ dừng hoặc tiếp tục thực hiện các lệnh của nó, kết thúc có hoặc không có kết xuất bộ nhớ hoặc thậm chí đơn giản là bỏ qua tín hiệu
Mặc dù được định nghĩa trong tiêu chuẩn POSIX, phản ứng thực sự phụ thuộc vào cách nhà phát triển viết tập lệnh và triển khai xử lý tín hiệu
Trong bài viết này, chúng tôi giải thích tín hiệu là gì, chỉ cho bạn cách gửi tín hiệu đến một quy trình khác từ dòng lệnh cũng như xử lý tín hiệu nhận được. Trong số các mô-đun khác, mã chương trình chủ yếu dựa trên mô-đun tín hiệu. Mô-đun này kết nối các tiêu đề C tương ứng của hệ điều hành của bạn với thế giới Python
Giới thiệu về tín hiệu
Trên hệ thống dựa trên UNIX, có ba loại tín hiệu
Tín hiệu hệ thống [lỗi phần cứng và hệ thống]. SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGKILL, SIGSEGV, SIGXCPU, SIGXFSZ, SIGIO
tín hiệu thiết bị. SIGHUP, SIGINT, SIGPIPE, SIGALRM, SIGCHLD, SIGCONT, SIGSTOP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH, SIGIO
Tín hiệu do người dùng xác định. SIGQUIT, SIGABRT, SIGUSR1, SIGUSR2, SIGTERM
Mỗi tín hiệu được biểu thị bằng một giá trị số nguyên và danh sách các tín hiệu khả dụng tương đối dài và không nhất quán giữa các biến thể UNIX/Linux khác nhau. Trên hệ thống Debian GNU/Linux, lệnh
$ kill -15 12345
2 hiển thị danh sách các tín hiệu như sau$ kill -l
1] SIGHUP 2] SIGINT 3] SIGQUIT 4] SIGILL 5] SIGTRAP
6] SIGABRT 7] SIGBUS 8] SIGFPE 9] SIGKILL 10] SIGUSR1
11] SIGSEGV 12] SIGUSR2 13] SIGPIPE 14] SIGALRM 15] SIGTERM
16] SIGSTKFLT 17] SIGCHLD 18] SIGCONT 19] SIGSTOP 20] SIGTSTP
21] SIGTTIN 22] SIGTTOU 23] SIGURG 24] SIGXCPU 25] SIGXFSZ
26] SIGVTALRM 27] SIGPROF 28] SIGWINCH 29] SIGIO 30] SIGPWR
31] SIGSYS 34] SIGRTMIN 35] SIGRTMIN+1 36] SIGRTMIN+2 37] SIGRTMIN+3
38] SIGRTMIN+4 39] SIGRTMIN+5 40] SIGRTMIN+6 41] SIGRTMIN+7 42] SIGRTMIN+8
43] SIGRTMIN+9 44] SIGRTMIN+10 45] SIGRTMIN+11 46] SIGRTMIN+12 47] SIGRTMIN+13
48] SIGRTMIN+14 49] SIGRTMIN+15 50] SIGRTMAX-14 51] SIGRTMAX-13 52] SIGRTMAX-12
53] SIGRTMAX-11 54] SIGRTMAX-10 55] SIGRTMAX-9 56] SIGRTMAX-8 57] SIGRTMAX-7
58] SIGRTMAX-6 59] SIGRTMAX-5 60] SIGRTMAX-4 61] SIGRTMAX-3 62] SIGRTMAX-2
63] SIGRTMAX-1 64] SIGRTMAX
Các tín hiệu từ 1 đến 15 được chuẩn hóa đại khái và có ý nghĩa như sau trên hầu hết các hệ thống Linux
- 1 [HÍT LÊN]. chấm dứt kết nối hoặc tải lại cấu hình cho daemon
- 2 [DẤU HIỆU]. ngắt phiên từ trạm đối thoại
- 3 [SIGQUIT]. kết thúc phiên từ trạm đối thoại
- 4 [SIGILL]. hướng dẫn bất hợp pháp đã được thực hiện
- 5 [SIGTRAP]. thực hiện một hướng dẫn duy nhất [bẫy]
- 6 [SIGABRT]. sự chấm dứt bất thường
- 7 [SIGBUS]. lỗi trên bus hệ thống
- 8 [SIGFPE]. lỗi dấu phẩy động
- 9 [SIGKILL]. ngay lập tức chấm dứt quá trình
- 10 [SIGUSR1]. tín hiệu do người dùng xác định
- 11 [SIGSEGV]. lỗi phân đoạn do truy cập bất hợp pháp một đoạn bộ nhớ
- 12 [SIGUSR2]. tín hiệu do người dùng xác định
- 13 [SIGPIPE]. viết vào một đường ống, và không ai đọc từ nó
- 14 [SIGALRM]. bộ đếm thời gian kết thúc [báo thức]
- 15 [SIGTERM]. kết thúc quá trình một cách nhẹ nhàng
Để gửi tín hiệu đến một quy trình trong thiết bị đầu cuối Linux, bạn gọi lệnh
$ kill -15 12345
3 với cả số tín hiệu [hoặc tên tín hiệu] từ danh sách trên và id của quy trình [pid]. Lệnh ví dụ sau gửi tín hiệu 15 [SIGTERM] đến quy trình có pid 12345$ kill -15 12345
Một cách tương đương là sử dụng tên tín hiệu thay vì số của nó
$ kill -SIGTERM 12345
Bạn chọn cách nào tùy thuộc vào cách nào thuận tiện hơn cho bạn. Cả hai cách đều có tác dụng như nhau. Kết quả là quá trình nhận được tín hiệu SIGTERM và kết thúc ngay lập tức
Sử dụng Thư viện tín hiệu Python
Kể từ Python 1. 4, thư viện
$ kill -15 12345
4 là thành phần thông thường của mọi bản phát hành Python. Để sử dụng thư viện $ kill -15 12345
4, trước tiên hãy nhập thư viện vào chương trình Python của bạn như sauimport signal
Việc nắm bắt và phản ứng đúng trên tín hiệu nhận được được thực hiện bằng chức năng gọi lại - cái gọi là trình xử lý tín hiệu. Một bộ xử lý tín hiệu khá đơn giản tên là
$ kill -15 12345
6 có thể được viết như saudef receiveSignal[signalNumber, frame]:
print['Received:', signalNumber]
return
Trình xử lý tín hiệu này không làm gì khác ngoài việc báo cáo số lượng tín hiệu nhận được. Bước tiếp theo là đăng ký các tín hiệu được bộ xử lý tín hiệu bắt. Đối với các chương trình Python, tất cả các tín hiệu [trừ 9, SIGKILL] có thể được bắt trong tập lệnh của bạn
Tiếp theo, chúng tôi thêm thông tin quy trình cho quy trình hiện tại và phát hiện id quy trình bằng methode
$ kill -15 12345
7 từ mô-đun $ kill -15 12345
8. Trong một vòng lặp $ kill -15 12345
9 vô tận, chúng tôi chờ đợi các tín hiệu đến. Chúng tôi triển khai điều này bằng cách sử dụng thêm hai mô-đun Python - os và time. Chúng tôi cũng nhập chúng vào đầu tập lệnh Python của mình$ kill -l
1] SIGHUP 2] SIGINT 3] SIGQUIT 4] SIGILL 5] SIGTRAP
6] SIGABRT 7] SIGBUS 8] SIGFPE 9] SIGKILL 10] SIGUSR1
11] SIGSEGV 12] SIGUSR2 13] SIGPIPE 14] SIGALRM 15] SIGTERM
16] SIGSTKFLT 17] SIGCHLD 18] SIGCONT 19] SIGSTOP 20] SIGTSTP
21] SIGTTIN 22] SIGTTOU 23] SIGURG 24] SIGXCPU 25] SIGXFSZ
26] SIGVTALRM 27] SIGPROF 28] SIGWINCH 29] SIGIO 30] SIGPWR
31] SIGSYS 34] SIGRTMIN 35] SIGRTMIN+1 36] SIGRTMIN+2 37] SIGRTMIN+3
38] SIGRTMIN+4 39] SIGRTMIN+5 40] SIGRTMIN+6 41] SIGRTMIN+7 42] SIGRTMIN+8
43] SIGRTMIN+9 44] SIGRTMIN+10 45] SIGRTMIN+11 46] SIGRTMIN+12 47] SIGRTMIN+13
48] SIGRTMIN+14 49] SIGRTMIN+15 50] SIGRTMAX-14 51] SIGRTMAX-13 52] SIGRTMAX-12
53] SIGRTMAX-11 54] SIGRTMAX-10 55] SIGRTMAX-9 56] SIGRTMAX-8 57] SIGRTMAX-7
58] SIGRTMAX-6 59] SIGRTMAX-5 60] SIGRTMAX-4 61] SIGRTMAX-3 62] SIGRTMAX-2
63] SIGRTMAX-1 64] SIGRTMAX
3Trong vòng lặp
$ kill -15 12345
9 của chương trình chính của chúng ta, câu lệnh in xuất ra "Đang chờ. ". Lệnh gọi hàm $ kill -SIGTERM 12345
1 khiến chương trình đợi trong ba giâyHãy xem hướng dẫn thực hành, thực tế của chúng tôi để học Git, với các phương pháp hay nhất, tiêu chuẩn được ngành chấp nhận và bao gồm bảng gian lận. Dừng các lệnh Git trên Google và thực sự tìm hiểu nó
Cuối cùng, chúng ta phải kiểm tra kịch bản của mình. Đã lưu tập lệnh dưới dạng
$ kill -SIGTERM 12345
2, chúng ta có thể gọi nó trong một thiết bị đầu cuối như sau$ kill -l
1] SIGHUP 2] SIGINT 3] SIGQUIT 4] SIGILL 5] SIGTRAP
6] SIGABRT 7] SIGBUS 8] SIGFPE 9] SIGKILL 10] SIGUSR1
11] SIGSEGV 12] SIGUSR2 13] SIGPIPE 14] SIGALRM 15] SIGTERM
16] SIGSTKFLT 17] SIGCHLD 18] SIGCONT 19] SIGSTOP 20] SIGTSTP
21] SIGTTIN 22] SIGTTOU 23] SIGURG 24] SIGXCPU 25] SIGXFSZ
26] SIGVTALRM 27] SIGPROF 28] SIGWINCH 29] SIGIO 30] SIGPWR
31] SIGSYS 34] SIGRTMIN 35] SIGRTMIN+1 36] SIGRTMIN+2 37] SIGRTMIN+3
38] SIGRTMIN+4 39] SIGRTMIN+5 40] SIGRTMIN+6 41] SIGRTMIN+7 42] SIGRTMIN+8
43] SIGRTMIN+9 44] SIGRTMIN+10 45] SIGRTMIN+11 46] SIGRTMIN+12 47] SIGRTMIN+13
48] SIGRTMIN+14 49] SIGRTMIN+15 50] SIGRTMAX-14 51] SIGRTMAX-13 52] SIGRTMAX-12
53] SIGRTMAX-11 54] SIGRTMAX-10 55] SIGRTMAX-9 56] SIGRTMAX-8 57] SIGRTMAX-7
58] SIGRTMAX-6 59] SIGRTMAX-5 60] SIGRTMAX-4 61] SIGRTMAX-3 62] SIGRTMAX-2
63] SIGRTMAX-1 64] SIGRTMAX
7Trong cửa sổ đầu cuối thứ hai, chúng tôi gửi tín hiệu đến quy trình. Chúng tôi xác định quy trình đầu tiên của mình - tập lệnh Python - theo id quy trình như được in trên màn hình, ở trên
$ kill -l
1] SIGHUP 2] SIGINT 3] SIGQUIT 4] SIGILL 5] SIGTRAP
6] SIGABRT 7] SIGBUS 8] SIGFPE 9] SIGKILL 10] SIGUSR1
11] SIGSEGV 12] SIGUSR2 13] SIGPIPE 14] SIGALRM 15] SIGTERM
16] SIGSTKFLT 17] SIGCHLD 18] SIGCONT 19] SIGSTOP 20] SIGTSTP
21] SIGTTIN 22] SIGTTOU 23] SIGURG 24] SIGXCPU 25] SIGXFSZ
26] SIGVTALRM 27] SIGPROF 28] SIGWINCH 29] SIGIO 30] SIGPWR
31] SIGSYS 34] SIGRTMIN 35] SIGRTMIN+1 36] SIGRTMIN+2 37] SIGRTMIN+3
38] SIGRTMIN+4 39] SIGRTMIN+5 40] SIGRTMIN+6 41] SIGRTMIN+7 42] SIGRTMIN+8
43] SIGRTMIN+9 44] SIGRTMIN+10 45] SIGRTMIN+11 46] SIGRTMIN+12 47] SIGRTMIN+13
48] SIGRTMIN+14 49] SIGRTMIN+15 50] SIGRTMAX-14 51] SIGRTMAX-13 52] SIGRTMAX-12
53] SIGRTMAX-11 54] SIGRTMAX-10 55] SIGRTMAX-9 56] SIGRTMAX-8 57] SIGRTMAX-7
58] SIGRTMAX-6 59] SIGRTMAX-5 60] SIGRTMAX-4 61] SIGRTMAX-3 62] SIGRTMAX-2
63] SIGRTMAX-1 64] SIGRTMAX
8Trình xử lý sự kiện tín hiệu trong chương trình Python của chúng tôi nhận tín hiệu mà chúng tôi đã gửi đến quy trình. Nó phản ứng tương ứng và chỉ cần xác nhận tín hiệu nhận được
$ kill -l
1] SIGHUP 2] SIGINT 3] SIGQUIT 4] SIGILL 5] SIGTRAP
6] SIGABRT 7] SIGBUS 8] SIGFPE 9] SIGKILL 10] SIGUSR1
11] SIGSEGV 12] SIGUSR2 13] SIGPIPE 14] SIGALRM 15] SIGTERM
16] SIGSTKFLT 17] SIGCHLD 18] SIGCONT 19] SIGSTOP 20] SIGTSTP
21] SIGTTIN 22] SIGTTOU 23] SIGURG 24] SIGXCPU 25] SIGXFSZ
26] SIGVTALRM 27] SIGPROF 28] SIGWINCH 29] SIGIO 30] SIGPWR
31] SIGSYS 34] SIGRTMIN 35] SIGRTMIN+1 36] SIGRTMIN+2 37] SIGRTMIN+3
38] SIGRTMIN+4 39] SIGRTMIN+5 40] SIGRTMIN+6 41] SIGRTMIN+7 42] SIGRTMIN+8
43] SIGRTMIN+9 44] SIGRTMIN+10 45] SIGRTMIN+11 46] SIGRTMIN+12 47] SIGRTMIN+13
48] SIGRTMIN+14 49] SIGRTMIN+15 50] SIGRTMAX-14 51] SIGRTMAX-13 52] SIGRTMAX-12
53] SIGRTMAX-11 54] SIGRTMAX-10 55] SIGRTMAX-9 56] SIGRTMAX-8 57] SIGRTMAX-7
58] SIGRTMAX-6 59] SIGRTMAX-5 60] SIGRTMAX-4 61] SIGRTMAX-3 62] SIGRTMAX-2
63] SIGRTMAX-1 64] SIGRTMAX
9Bỏ qua tín hiệu
Mô-đun tín hiệu xác định các cách để bỏ qua các tín hiệu nhận được. Để làm được điều đó, tín hiệu phải được kết nối với chức năng được xác định trước
$ kill -SIGTERM 12345
3. Ví dụ dưới đây chứng minh điều đó, và kết quả là chương trình Python không thể bị gián đoạn bởi $ kill -SIGTERM 12345
4 nữa. Để dừng tập lệnh Python, một cách khác đã được triển khai trong tập lệnh ví dụ - tín hiệu SIGUSR1 chấm dứt tập lệnh Python. Hơn nữa, thay vì một vòng lặp vô tận, chúng tôi sử dụng phương pháp $ kill -SIGTERM 12345
5. Nó chỉ chờ tín hiệu được nhậnXử lý tín hiệu đúng cách
Trình xử lý tín hiệu mà chúng tôi đã sử dụng cho đến nay khá đơn giản và chỉ báo cáo tín hiệu đã nhận. Điều này cho chúng tôi thấy rằng giao diện của tập lệnh Python của chúng tôi đang hoạt động tốt. Hãy cải thiện nó
Bắt tín hiệu đã là một cơ sở tốt nhưng cần một số cải tiến để tuân thủ các quy tắc của tiêu chuẩn POSIX. Để có độ chính xác cao hơn, mỗi tín hiệu cần có phản ứng thích hợp [xem danh sách ở trên]. Điều này có nghĩa là trình xử lý tín hiệu trong tập lệnh Python của chúng ta cần được mở rộng theo một quy trình cụ thể cho mỗi tín hiệu. Điều này hoạt động tốt nhất nếu chúng ta hiểu tín hiệu làm gì và phản ứng thông thường là gì. Quá trình nhận tín hiệu 1, 2, 9 hoặc 15 sẽ kết thúc. Trong bất kỳ trường hợp nào khác, dự kiến cũng sẽ viết một kết xuất lõi
Cho đến bây giờ, chúng tôi đã triển khai một quy trình duy nhất bao gồm tất cả các tín hiệu và xử lý chúng theo cùng một cách. Bước tiếp theo là thực hiện một quy trình riêng cho mỗi tín hiệu. Mã ví dụ sau minh họa điều này cho các tín hiệu 1 [SIGHUP] và 15 [SIGTERM]
$ kill -15 12345
3Hai chức năng trên được kết nối với các tín hiệu như sau
$ kill -15 12345
0Chạy tập lệnh Python và gửi tín hiệu 1 [SIGHUP] theo sau là tín hiệu 15 [SIGTERM] bằng lệnh UNIX
$ kill -SIGTERM 12345
6 và $ kill -SIGTERM 12345
7 dẫn đến đầu ra sau$ kill -15 12345
1Tập lệnh nhận tín hiệu và xử lý chúng đúng cách. Để rõ ràng, đây là toàn bộ kịch bản
Đọc thêm
Sử dụng mô-đun
$ kill -15 12345
4 và trình xử lý sự kiện phù hợp, việc bắt tín hiệu tương đối dễ dàng. Biết ý nghĩa của các tín hiệu khác nhau và để phản ứng đúng như được định nghĩa trong tiêu chuẩn POSIX là bước tiếp theo. Nó yêu cầu trình xử lý sự kiện phân biệt giữa các tín hiệu khác nhau và có một thói quen riêng cho tất cả chúng