signal --- Đặt trình xử lý cho các sự kiện không đồng bộ

Source code: Lib/signal.py


Mô-đun này cung cấp cơ chế sử dụng trình xử lý tín hiệu trong Python.

Quy tắc chung

Hàm signal.signal() cho phép xác định các trình xử lý tùy chỉnh sẽ được thực thi khi nhận được tín hiệu. Một số lượng nhỏ trình xử lý mặc định được cài đặt: SIGPIPE bị bỏ qua (vì vậy lỗi ghi trên đường ống và ổ cắm có thể được báo cáo là ngoại lệ Python thông thường) và SIGINT được dịch thành ngoại lệ KeyboardInterrupt nếu quy trình gốc không thay đổi.

Trình xử lý cho một tín hiệu cụ thể, sau khi được đặt, vẫn được cài đặt cho đến khi được đặt lại rõ ràng (Python mô phỏng giao diện kiểu BSD bất kể cách triển khai cơ bản), ngoại trừ trình xử lý dành cho SIGCHLD, tuân theo cách triển khai cơ bản.

Trên nền tảng WebAssembly, các tín hiệu được mô phỏng và do đó hoạt động khác nhau. Một số chức năng và tín hiệu không có sẵn trên các nền tảng này.

Thực thi các trình xử lý tín hiệu Python

Trình xử lý tín hiệu Python không được thực thi bên trong trình xử lý tín hiệu cấp thấp (C). Thay vào đó, trình xử lý tín hiệu cấp thấp sẽ đặt một cờ báo cho virtual machine thực thi trình xử lý tín hiệu Python tương ứng vào thời điểm sau đó (ví dụ: ở lệnh bytecode tiếp theo). Điều này có hậu quả:

  • Sẽ chẳng có ý nghĩa gì khi phát hiện các lỗi đồng bộ như SIGFPE hoặc SIGSEGV do thao tác không hợp lệ trong mã C gây ra. Python sẽ quay trở lại từ trình xử lý tín hiệu về mã C, điều này có khả năng lại tăng tín hiệu tương tự, khiến Python dường như bị treo. Từ Python 3.3 trở đi, bạn có thể sử dụng mô-đun faulthandler để báo cáo lỗi đồng bộ.

  • Một phép tính dài hạn được triển khai hoàn toàn bằng C (chẳng hạn như khớp biểu thức chính quy trên một lượng lớn văn bản) có thể chạy không bị gián đoạn trong một khoảng thời gian tùy ý, bất kể bất kỳ tín hiệu nào nhận được. Trình xử lý tín hiệu Python sẽ được gọi khi quá trình tính toán kết thúc.

  • Nếu trình xử lý đưa ra một ngoại lệ, nó sẽ được đưa ra "bất ngờ" trong luồng chính. Xem note below để thảo luận.

Tín hiệu và chủ đề

Trình xử lý tín hiệu Python luôn được thực thi trong luồng Python chính của trình thông dịch chính, ngay cả khi tín hiệu được nhận trong luồng khác. Điều này có nghĩa là tín hiệu không thể được sử dụng làm phương tiện liên lạc giữa các luồng. Thay vào đó, bạn có thể sử dụng các nguyên hàm đồng bộ hóa từ mô-đun threading.

Ngoài ra, chỉ luồng chính của trình thông dịch chính mới được phép đặt bộ xử lý tín hiệu mới.

Cảnh báo

Không nên sử dụng các nguyên hàm đồng bộ hóa như threading.Lock trong trình xử lý tín hiệu. Làm như vậy có thể dẫn đến những bế tắc không mong muốn.

Nội dung mô-đun

Thay đổi trong phiên bản 3.5: Các hằng số liên quan đến tín hiệu (SIG*), bộ xử lý (SIG_DFL, SIG_IGN) và sigmask (SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK) được liệt kê bên dưới đã được chuyển thành enums (Signals, HandlersSigmasks tương ứng). Các hàm getsignal(), pthread_sigmask(), sigpending()sigwait() trả về enums mà con người có thể đọc được dưới dạng đối tượng Signals.

Mô-đun tín hiệu xác định ba enum:

class signal.Signals

enum.IntEnum tập hợp các hằng số SIG* và các hằng số CTRL_*.

Added in version 3.5.

class signal.Handlers

enum.IntEnum tập hợp các hằng số SIG_DFLSIG_IGN.

Added in version 3.5.

class signal.Sigmasks

enum.IntEnum tập hợp các hằng số SIG_BLOCK, SIG_UNBLOCKSIG_SETMASK.

sẵn có: Unix.

Xem trang hướng dẫn sigprocmask(2)pthread_sigmask(3) để biết thêm thông tin.

Added in version 3.5.

Các biến được xác định trong mô-đun signal là:

signal.SIG_DFL

Đây là một trong hai tùy chọn xử lý tín hiệu tiêu chuẩn; nó sẽ chỉ thực hiện chức năng mặc định cho tín hiệu. Ví dụ: trên hầu hết các hệ thống, hành động mặc định cho SIGQUIT là kết xuất lõi và thoát, trong khi hành động mặc định cho SIGCHLD chỉ đơn giản là bỏ qua nó.

signal.SIG_IGN

Đây là một trình xử lý tín hiệu tiêu chuẩn khác, sẽ đơn giản bỏ qua tín hiệu đã cho.

signal.SIGABRT

Hủy bỏ tín hiệu từ abort(3).

signal.SIGALRM

Tín hiệu hẹn giờ từ alarm(2).

sẵn có: Unix.

signal.SIGBREAK

Ngắt từ bàn phím (CTRL + BREAK).

sẵn có: Windows.

signal.SIGBUS

Lỗi xe buýt (truy cập bộ nhớ kém).

sẵn có: Unix.

signal.SIGCHLD

Quá trình con dừng lại hoặc chấm dứt.

sẵn có: Unix.

signal.SIGCLD

Bí danh cho SIGCHLD.

sẵn có: not macOS.

signal.SIGCONT

Tiếp tục quá trình nếu nó hiện đang dừng

sẵn có: Unix.

signal.SIGFPE

Ngoại lệ dấu phẩy động. Ví dụ: chia cho số 0.

Xem thêm

ZeroDivisionError được nâng lên khi đối số thứ hai của phép chia hoặc phép toán modulo bằng 0.

signal.SIGHUP

Phát hiện treo máy trên thiết bị đầu cuối điều khiển hoặc quá trình điều khiển bị chết.

sẵn có: Unix.

signal.SIGILL

Hướng dẫn bất hợp pháp.

signal.SIGINT

Ngắt từ bàn phím (CTRL + C).

Hành động mặc định là tăng KeyboardInterrupt.

signal.SIGKILL

Tín hiệu tiêu diệt.

Nó không thể bị bắt, bị chặn hoặc bỏ qua.

sẵn có: Unix.

signal.SIGPIPE

Ống bị hỏng: ghi vào ống không có đầu đọc.

Hành động mặc định là bỏ qua tín hiệu.

sẵn có: Unix.

signal.SIGPROF

Hồ sơ hẹn giờ đã hết hạn.

sẵn có: Unix.

signal.SIGQUIT

Tín hiệu thoát khỏi thiết bị đầu cuối.

sẵn có: Unix.

signal.SIGSEGV

Lỗi phân đoạn: tham chiếu bộ nhớ không hợp lệ.

signal.SIGSTOP

Dừng thực thi (không thể bắt hoặc bỏ qua).

sẵn có: Unix.

signal.SIGSTKFLT

Lỗi ngăn xếp trên bộ đồng xử lý. Nhân Linux không đưa ra tín hiệu này: nó chỉ có thể được nâng lên trong không gian người dùng.

sẵn có: Linux.

Trên các kiến trúc có tín hiệu sẵn có. Xem trang man signal(7) để biết thêm thông tin.

Added in version 3.11.

signal.SIGTERM

Tín hiệu kết thúc.

signal.SIGUSR1

Tín hiệu do người dùng xác định 1.

sẵn có: Unix.

signal.SIGUSR2

Tín hiệu do người dùng xác định 2.

sẵn có: Unix.

signal.SIGVTALRM

Hẹn giờ ảo đã hết hạn.

sẵn có: Unix.

signal.SIGWINCH

Tín hiệu thay đổi kích thước cửa sổ

sẵn có: Unix.

signal.SIGXCPU

CPU đã vượt quá giới hạn thời gian.

sẵn có: Unix.

SIG*

Tất cả các số tín hiệu được xác định một cách tượng trưng. Ví dụ: tín hiệu cúp máy được xác định là signal.SIGHUP; tên biến giống hệt với tên được sử dụng trong chương trình C, như được tìm thấy trong <signal.h>. Trang man Unix cho 'signal' liệt kê các tín hiệu hiện có (trên một số hệ thống, đây là signal(2), trên các hệ thống khác, danh sách này là signal(7)). Lưu ý rằng không phải tất cả các hệ thống đều xác định cùng một bộ tên tín hiệu; chỉ những tên do hệ thống xác định mới được xác định bởi mô-đun này.

signal.CTRL_C_EVENT

Tín hiệu tương ứng với sự kiện gõ phím Ctrl+C. Tín hiệu này chỉ có thể được sử dụng với os.kill().

sẵn có: Windows.

Added in version 3.2.

signal.CTRL_BREAK_EVENT

Tín hiệu tương ứng với sự kiện gõ phím Ctrl+Break. Tín hiệu này chỉ có thể được sử dụng với os.kill().

sẵn có: Windows.

Added in version 3.2.

signal.NSIG

Nhiều hơn số lượng tín hiệu cao nhất. Sử dụng valid_signals() để nhận số tín hiệu hợp lệ.

signal.ITIMER_REAL

Giảm bộ đếm thời gian theo thời gian thực và cung cấp SIGALRM khi hết hạn.

signal.ITIMER_VIRTUAL

Chỉ giảm bộ đếm thời gian khi quá trình đang thực thi và cung cấp SIGVTALRM khi hết hạn.

signal.ITIMER_PROF

Giảm khoảng thời gian định giờ cả khi quá trình thực thi và khi hệ thống thực thi thay mặt cho quá trình đó. Cùng với ITIMER_VIRTUAL, bộ hẹn giờ này thường được sử dụng để lập hồ sơ thời gian mà ứng dụng dành cho không gian người dùng và kernel. SIGPROF được giao khi hết hạn.

signal.SIG_BLOCK

Một giá trị có thể có của tham số how thành pthread_sigmask() cho biết các tín hiệu sẽ bị chặn.

Added in version 3.3.

signal.SIG_UNBLOCK

Một giá trị có thể có của tham số how thành pthread_sigmask() cho biết rằng các tín hiệu sẽ được bỏ chặn.

Added in version 3.3.

signal.SIG_SETMASK

Một giá trị có thể có của tham số how thành pthread_sigmask() cho biết mặt nạ tín hiệu sẽ được thay thế.

Added in version 3.3.

Mô-đun signal xác định một ngoại lệ:

exception signal.ItimerError

Được đưa ra để báo hiệu lỗi từ quá trình triển khai setitimer() hoặc getitimer() cơ bản. Có thể xảy ra lỗi này nếu bộ hẹn giờ ngắt quãng không hợp lệ hoặc thời gian âm được chuyển tới setitimer(). Lỗi này là một kiểu con của OSError.

Added in version 3.3: Lỗi này từng là một kiểu con của IOError, hiện là bí danh của OSError.

Mô-đun signal xác định các chức năng sau:

signal.alarm(time)

Nếu time khác 0, hàm này yêu cầu tín hiệu SIGALRM được gửi đến quy trình sau time giây. Mọi báo thức đã lên lịch trước đó đều bị hủy (chỉ có thể lập lịch một báo thức bất cứ lúc nào). Giá trị được trả về sau đó là số giây trước khi bất kỳ cảnh báo nào được đặt trước đó được gửi đi. Nếu time bằng 0, không có cảnh báo nào được lên lịch và mọi cảnh báo đã lên lịch sẽ bị hủy. Nếu giá trị trả về bằng 0 thì hiện tại không có cảnh báo nào được lên lịch.

sẵn có: Unix.

Xem trang man alarm(2) để biết thêm thông tin.

signal.getsignal(signalnum)

Trả về bộ xử lý tín hiệu hiện tại cho tín hiệu signalnum. Giá trị trả về có thể là một đối tượng Python có thể gọi được hoặc một trong các giá trị đặc biệt signal.SIG_IGN, signal.SIG_DFL hoặc None. Ở đây, signal.SIG_IGN có nghĩa là tín hiệu đã bị bỏ qua trước đó, signal.SIG_DFL có nghĩa là cách xử lý tín hiệu mặc định đã được sử dụng trước đó và None có nghĩa là trình xử lý tín hiệu trước đó chưa được cài đặt từ Python.

signal.strsignal(signalnum)

Trả về mô tả của tín hiệu signalnum, chẳng hạn như "Ngắt" cho SIGINT. Trả về None nếu signalnum không có mô tả. Tăng ValueError nếu signalnum không hợp lệ.

Added in version 3.8.

signal.valid_signals()

Trả về bộ số tín hiệu hợp lệ trên nền tảng này. Giá trị này có thể nhỏ hơn range(1, NSIG) nếu một số tín hiệu được hệ thống dành riêng để sử dụng nội bộ.

Added in version 3.8.

signal.pause()

Làm cho quá trình ngủ cho đến khi nhận được tín hiệu; trình xử lý thích hợp sau đó sẽ được gọi. Không trả lại gì cả.

sẵn có: Unix.

Xem trang man signal(2) để biết thêm thông tin.

Xem thêm sigwait(), sigwaitinfo(), sigtimedwait()sigpending().

signal.raise_signal(signum)

Gửi tín hiệu đến quá trình gọi. Không trả lại gì cả.

Added in version 3.8.

signal.pidfd_send_signal(pidfd, sig, siginfo=None, flags=0)

Gửi tín hiệu sig đến quy trình được tham chiếu bởi bộ mô tả tệp pidfd. Python hiện không hỗ trợ tham số siginfo; nó phải là None. Đối số flags được cung cấp cho các tiện ích mở rộng trong tương lai; hiện tại không có giá trị cờ nào được xác định.

Xem trang man pidfd_send_signal(2) để biết thêm thông tin.

sẵn có: Linux >= 5.1, Android >= build-time API level 31

Added in version 3.9.

signal.pthread_kill(thread_id, signalnum)

Gửi tín hiệu signalnum đến thread thread_id, một thread khác trong cùng tiến trình với người gọi. Chuỗi đích có thể thực thi bất kỳ mã nào (Python hoặc không). Tuy nhiên, nếu luồng đích đang thực thi trình thông dịch Python thì trình xử lý tín hiệu Python sẽ là executed by the main thread of the main interpreter. Do đó, điểm duy nhất để gửi tín hiệu đến một luồng Python cụ thể là buộc lệnh gọi hệ thống đang chạy không thành công với InterruptedError.

Sử dụng thuộc tính threading.get_ident() hoặc ident của đối tượng threading.Thread để nhận giá trị phù hợp cho thread_id.

Nếu signalnum bằng 0 thì không có tín hiệu nào được gửi nhưng việc kiểm tra lỗi vẫn được thực hiện; điều này có thể được sử dụng để kiểm tra xem luồng mục tiêu có còn chạy hay không.

Tăng một auditing event signal.pthread_kill với các đối số thread_id, signalnum.

sẵn có: Unix.

Xem trang man pthread_kill(3) để biết thêm thông tin.

Xem thêm os.kill().

Added in version 3.3.

signal.pthread_sigmask(how, mask)

Tìm nạp và/hoặc thay đổi mặt nạ tín hiệu của chuỗi cuộc gọi. Mặt nạ tín hiệu là tập hợp các tín hiệu mà việc gửi tín hiệu hiện đang bị chặn đối với người gọi. Trả lại mặt nạ tín hiệu cũ dưới dạng một tập hợp tín hiệu.

Hoạt động của cuộc gọi phụ thuộc vào giá trị của how, như sau.

  • SIG_BLOCK: Tập hợp các tín hiệu bị chặn là sự kết hợp của tập hợp hiện tại và đối số mask.

  • SIG_UNBLOCK: Các tín hiệu trong mask bị xóa khỏi nhóm tín hiệu bị chặn hiện tại. Được phép cố gắng bỏ chặn tín hiệu không bị chặn.

  • SIG_SETMASK: Tập hợp các tín hiệu bị chặn được đặt thành đối số mask.

mask là tập hợp các số tín hiệu (ví dụ: {signal.SIGINT, signal.SIGTERM}). Sử dụng valid_signals() cho mặt nạ đầy đủ bao gồm tất cả các tín hiệu.

Ví dụ: signal.pthread_sigmask(signal.SIG_BLOCK, []) đọc mặt nạ tín hiệu của chuỗi cuộc gọi.

SIGKILLSIGSTOP không thể bị chặn.

sẵn có: Unix.

Xem trang hướng dẫn sigprocmask(2)pthread_sigmask(3) để biết thêm thông tin.

Xem thêm pause(), sigpending()sigwait().

Added in version 3.3.

signal.setitimer(which, seconds, interval=0.0)

Đặt bộ hẹn giờ khoảng thời gian nhất định (một trong các signal.ITIMER_REAL, signal.ITIMER_VIRTUAL hoặc signal.ITIMER_PROF) do which chỉ định để kích hoạt sau seconds (float được chấp nhận, khác với alarm()) và sau đó cứ mỗi interval giây (nếu interval khác 0). Có thể xóa bộ định thời khoảng thời gian do which chỉ định bằng cách đặt seconds về 0.

Khi bộ hẹn giờ ngắt quãng kích hoạt, tín hiệu sẽ được gửi đến quy trình. Tín hiệu được gửi phụ thuộc vào bộ hẹn giờ được sử dụng; signal.ITIMER_REAL sẽ gửi SIGALRM, signal.ITIMER_VIRTUAL gửi SIGVTALRMsignal.ITIMER_PROF sẽ gửi SIGPROF.

Các giá trị cũ được trả về dưới dạng một bộ: (độ trễ, khoảng thời gian).

Cố gắng vượt qua bộ hẹn giờ khoảng thời gian không hợp lệ sẽ gây ra ItimerError.

sẵn có: Unix.

signal.getitimer(which)

Trả về giá trị hiện tại của bộ định thời khoảng thời gian nhất định được chỉ định bởi which.

sẵn có: Unix.

signal.set_wakeup_fd(fd, *, warn_on_full_buffer=True)

Đặt bộ mô tả tệp đánh thức thành fd. Khi nhận được tín hiệu mà chương trình của bạn đã đăng ký bộ xử lý tín hiệu, số tín hiệu sẽ được ghi dưới dạng một byte vào fd. Nếu bạn chưa đăng ký trình xử lý tín hiệu cho các tín hiệu mà bạn quan tâm thì sẽ không có gì được ghi vào fd đánh thức. Thư viện có thể sử dụng tính năng này để đánh thức cuộc thăm dò ý kiến ​​hoặc cuộc gọi chọn lọc, cho phép tín hiệu được xử lý hoàn toàn.

Fd đánh thức cũ được trả về (hoặc -1 nếu đánh thức bộ mô tả tệp không được bật). Nếu fd là -1, việc đánh thức bộ mô tả tập tin bị tắt. Nếu không phải -1, fd phải không bị chặn. Tùy thuộc vào thư viện để xóa bất kỳ byte nào khỏi fd trước khi gọi cuộc thăm dò ý kiến ​​hoặc chọn lại.

Khi chủ đề được bật, chức năng này chỉ có thể được gọi từ the main thread of the main interpreter; cố gắng gọi nó từ các luồng khác sẽ gây ra ngoại lệ ValueError.

Có hai cách phổ biến để sử dụng chức năng này. Trong cả hai phương pháp, bạn sử dụng fd để đánh thức khi có tín hiệu đến, nhưng sau đó chúng khác nhau ở cách xác định tín hiệu which hoặc các tín hiệu đã đến.

Trong cách tiếp cận đầu tiên, chúng tôi đọc dữ liệu từ bộ đệm của fd và các giá trị byte cung cấp cho bạn các số tín hiệu. Điều này rất đơn giản, nhưng trong một số ít trường hợp, nó có thể gặp sự cố: nhìn chung fd sẽ có một lượng không gian bộ đệm hạn chế và nếu có quá nhiều tín hiệu đến quá nhanh thì bộ đệm có thể đầy và một số tín hiệu có thể bị mất. Nếu bạn sử dụng phương pháp này thì bạn nên đặt warn_on_full_buffer=True, điều này ít nhất sẽ khiến cảnh báo được in ra stderr khi mất tín hiệu.

Trong cách tiếp cận thứ hai, chúng tôi sử dụng Wakeup fd only để đánh thức và bỏ qua các giá trị byte thực tế. Trong trường hợp này, tất cả những gì chúng ta quan tâm là liệu bộ đệm của fd trống hay không trống; bộ đệm đầy hoàn toàn không cho thấy có vấn đề gì. Nếu sử dụng phương pháp này thì bạn nên đặt warn_on_full_buffer=False để người dùng không bị nhầm lẫn bởi các thông báo cảnh báo giả mạo.

Thay đổi trong phiên bản 3.5: Trên Windows, chức năng này hiện cũng hỗ trợ các tay cầm ổ cắm.

Thay đổi trong phiên bản 3.7: Đã thêm tham số warn_on_full_buffer.

signal.siginterrupt(signalnum, flag)

Thay đổi hành vi khởi động lại cuộc gọi hệ thống: nếu flagFalse, các cuộc gọi hệ thống sẽ được khởi động lại khi bị gián đoạn bởi tín hiệu signalnum, nếu không các cuộc gọi hệ thống sẽ bị gián đoạn. Không trả lại gì cả.

sẵn có: Unix.

Xem trang man siginterrupt(3) để biết thêm thông tin.

Lưu ý rằng việc cài đặt trình xử lý tín hiệu với signal() sẽ đặt lại hành vi khởi động lại thành có thể gián đoạn bằng cách gọi ngầm siginterrupt() với giá trị flag thực cho tín hiệu đã cho.

signal.signal(signalnum, handler)

Đặt bộ xử lý tín hiệu signalnum thành hàm handler. handler có thể là một đối tượng Python có thể gọi được với hai đối số (xem bên dưới) hoặc một trong các giá trị đặc biệt signal.SIG_IGN hoặc signal.SIG_DFL. Trình xử lý tín hiệu trước đó sẽ được trả về (xem mô tả về getsignal() ở trên). (Xem trang Unix signal(2) để biết thêm thông tin.)

Khi chủ đề được bật, chức năng này chỉ có thể được gọi từ the main thread of the main interpreter; cố gắng gọi nó từ các luồng khác sẽ gây ra ngoại lệ ValueError.

handler được gọi với hai đối số: số tín hiệu và khung ngăn xếp hiện tại (None hoặc đối tượng khung; để biết mô tả về đối tượng khung, hãy xem description in the type hierarchy hoặc xem mô tả thuộc tính trong mô-đun inspect).

Trên Windows, signal() chỉ có thể được gọi bằng SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM hoặc SIGBREAK. Một ValueError sẽ được nâng lên trong mọi trường hợp khác. Lưu ý rằng không phải tất cả các hệ thống đều xác định cùng một bộ tên tín hiệu; một AttributeError sẽ được nâng lên nếu tên tín hiệu không được xác định là hằng số mức mô-đun SIG*.

signal.sigpending()

Kiểm tra tập hợp các tín hiệu đang chờ gửi đến luồng đang gọi (tức là các tín hiệu đã được đưa ra trong khi bị chặn). Trả về tập hợp các tín hiệu đang chờ xử lý.

sẵn có: Unix.

Xem trang man sigpending(2) để biết thêm thông tin.

Xem thêm pause(), pthread_sigmask()sigwait().

Added in version 3.3.

signal.sigwait(sigset)

Tạm dừng thực thi luồng đang gọi cho đến khi phân phối một trong các tín hiệu được chỉ định trong bộ tín hiệu sigset. Hàm chấp nhận tín hiệu (xóa nó khỏi danh sách tín hiệu đang chờ xử lý) và trả về số tín hiệu.

sẵn có: Unix.

Xem trang man sigwait(3) để biết thêm thông tin.

Xem thêm pause(), pthread_sigmask(), sigpending(), sigwaitinfo()sigtimedwait().

Added in version 3.3.

signal.sigwaitinfo(sigset)

Tạm dừng thực thi luồng đang gọi cho đến khi phân phối một trong các tín hiệu được chỉ định trong bộ tín hiệu sigset. Hàm chấp nhận tín hiệu và xóa nó khỏi danh sách tín hiệu đang chờ xử lý. Nếu một trong các tín hiệu trong sigset đang chờ xử lý cho luồng gọi, hàm sẽ trả về ngay lập tức với thông tin về tín hiệu đó. Bộ xử lý tín hiệu không được gọi cho tín hiệu được gửi. Hàm này sẽ tăng InterruptedError nếu nó bị gián đoạn bởi tín hiệu không thuộc sigset.

Giá trị trả về là một đối tượng biểu thị dữ liệu chứa trong cấu trúc siginfo_t, cụ thể là: si_signo, si_code, si_errno, si_pid, si_uid, si_status, si_band.

sẵn có: Unix.

Xem trang man sigwaitinfo(2) để biết thêm thông tin.

Xem thêm pause(), sigwait()sigtimedwait().

Added in version 3.3.

Thay đổi trong phiên bản 3.5: Chức năng này hiện được thử lại nếu bị gián đoạn bởi tín hiệu không thuộc sigset và trình xử lý tín hiệu không đưa ra ngoại lệ (xem PEP 475 để biết lý do).

signal.sigtimedwait(sigset, timeout)

Giống như sigwaitinfo(), nhưng có thêm một đối số timeout chỉ định thời gian chờ. Nếu timeout được chỉ định là 0, một cuộc thăm dò sẽ được thực hiện. Trả về None nếu hết thời gian chờ.

sẵn có: Unix.

Xem trang man sigtimedwait(2) để biết thêm thông tin.

Xem thêm pause(), sigwait()sigwaitinfo().

Added in version 3.3.

Thay đổi trong phiên bản 3.5: Hàm này hiện được thử lại với timeout được tính toán lại nếu bị gián đoạn bởi tín hiệu không thuộc sigset và trình xử lý tín hiệu không đưa ra ngoại lệ (xem PEP 475 để biết lý do).

Ví dụ

Đây là một chương trình ví dụ tối thiểu. Nó sử dụng chức năng alarm() để giới hạn thời gian chờ mở tệp; điều này hữu ích nếu tệp dành cho một thiết bị nối tiếp có thể không được bật, điều này thường khiến os.open() bị treo vô thời hạn. Giải pháp là đặt báo thức 5 giây trước khi mở tệp; nếu thao tác mất quá nhiều thời gian, tín hiệu cảnh báo sẽ được gửi và trình xử lý sẽ đưa ra một ngoại lệ.

tín hiệu nhập khẩu, hệ điều hành

trình xử  def (dấu hiệu, khung):
    signame = signal.Signals(signum).name
    print(f'Trình xử lý tín hiệu được gọi với tín hiệu {signame} ({signum})')
    raise OSError("Không thể mở thiết bị!")

# Set bộ xử lý tín hiệu và cảnh báo 5 giây
signal.signal(signal.SIGALRM, trình xử )
tín hiệu.alarm(5)

# This open() có thể bị treo vô thời hạn
fd = os.open('/dev/ttyS0', os.O_RDWR)

signal.alarm(0) # Disable báo động

Lưu ý về SIGPIPE

Việc chuyển đầu ra chương trình của bạn tới các công cụ như head(1) sẽ khiến tín hiệu SIGPIPE được gửi đến quy trình của bạn khi bộ thu đầu ra tiêu chuẩn của nó đóng sớm. Điều này dẫn đến một ngoại lệ như BrokenPipeError: [Errno 32] Broken pipe. Để xử lý trường hợp này, hãy bọc điểm vào của bạn để bắt ngoại lệ này như sau

hệ điều hành nhập khẩu
hệ thống nhập khẩu

chắc chắn chính():
    thử:
        đầu ra lớn # simulate (mã của bạn thay thế vòng lặp này)
        cho x trong phạm vi (10000):
            in ("y")
        # flush xuất ra ở đây để buộc SIGPIPE được kích hoạt
        # while bên trong khối thử này.
        sys.stdout.flush()
    ngoại trừ BrokenPipeError:
        # Python xóa các luồng tiêu chuẩn khi thoát; chuyển hướng đầu ra còn lại
        # to devnull để tránh BrokenPipeError khác khi tắt máy
        devnull = os.open(os.devnull, os.O_WRONLY)
        os.dup2(devnull, sys.stdout.fileno())
        sys.exit(1) # Python thoát với mã lỗi 1 trên EPIPE

nếu __name__ == '__main__':
    chính()

Không đặt vị trí của SIGPIPE thành SIG_DFL để tránh BrokenPipeError. Làm như vậy sẽ khiến chương trình của bạn thoát ra bất ngờ bất cứ khi nào bất kỳ kết nối ổ cắm nào bị gián đoạn trong khi chương trình của bạn vẫn đang ghi vào đó.

Lưu ý về Trình xử lý tín hiệu và ngoại lệ

Nếu trình xử lý tín hiệu đưa ra một ngoại lệ, ngoại lệ đó sẽ được truyền đến luồng chính và có thể được đưa ra sau bất kỳ lệnh bytecode nào. Đáng chú ý nhất là KeyboardInterrupt có thể xuất hiện bất kỳ lúc nào trong quá trình thực thi. Hầu hết mã Python, bao gồm cả thư viện tiêu chuẩn, không thể chống lại điều này một cách mạnh mẽ và do đó, KeyboardInterrupt (hoặc bất kỳ ngoại lệ nào khác do trình xử lý tín hiệu) có thể trong một số trường hợp hiếm hoi khiến chương trình ở trạng thái không mong muốn.

Để minh họa vấn đề này, hãy xem xét đoạn mã sau:

lớp SpamContext:
    định nghĩa __init__(tự):
        self.lock = threading.Lock()

    chắc chắn __enter__(tự):
        # If Bàn phím bị gián đoạn xảy ra ở đây, mọi thứ đều ổn
        self.lock.acquire()
        # If Bàn phím bị gián đoạn xảy ra ở đây, __exit__ sẽ không được gọi
        ...
        # KeyboardInterrupt có thể xảy ra ngay trước khi hàm trả về

    def __exit__(self, exc_type, exc_val, exc_tb):
        ...
        self.lock.release()

Đối với nhiều chương trình, đặc biệt là những chương trình chỉ muốn thoát trên KeyboardInterrupt, đây không phải là vấn đề, nhưng các ứng dụng phức tạp hoặc yêu cầu độ tin cậy cao nên tránh đưa ra ngoại lệ từ bộ xử lý tín hiệu. Họ cũng nên tránh bắt gặp KeyboardInterrupt như một cách tắt máy một cách nhẹ nhàng. Thay vào đó, họ nên cài đặt trình xử lý SIGINT của riêng mình. Dưới đây là ví dụ về máy chủ HTTP tránh KeyboardInterrupt:

tín hiệu nhập khẩu
 cắm nhập khẩu
từ bộ chọn nhập DefaultSelector, EVENT_READ
từ http.server nhập HTTPServer, SimpleHTTPRequestHandler

ngắt_đọc, ngắt_write = socket.socketpair()

trình xử  def (dấu hiệu, khung):
    print('Trình xử lý tín hiệu được gọi bằng tín hiệu', signum)
    ngắt_write.send(b'\0')
signal.signal(signal.SIGINT, trình xử )

def phục vụ_forver(httpd):
    sel = Bộ chọn mặc định()
    sel.register(interrupt_read, EVENT_READ)
    sel.register(httpd, EVENT_READ)

    trong khi Đúng:
        cho khóa, _ trong sel.select():
            nếu key.fileobj == ngắt_read:
                ngắt_read.recv(1)
                trở về
            nếu key.fileobj == httpd:
                httpd.handle_request()

print("Phục vụ trên cổng 8000")
httpd = HTTPServer(('', 8000), SimpleHTTPRequestHandler)
phục vụ_forever(httpd)
print("Tắt máy...")