2008-09-20 34 views
9

Chương trình sau đây rất đơn giản: nó xuất ra một chấm mỗi nửa giây. Nếu nó nhận được SIGQUIT, nó sẽ xuất ra mười Q s. Nếu mà nó nhận được một SIGTSTP(Ctrl - Z), nó ra mười Z s.Tai ương tín hiệu Python: xử lý SIGQUIT trì hoãn thực hiện nếu SIGQUIT nhận được trong khi thực hiện một trình xử lý tín hiệu khác?

Nếu mà nó nhận được một SIGTSTP khi in Q s, nó sẽ in mười Z s sau khi hoàn thành công việc với mười Q s. Đây là một điều tốt.

Tuy nhiên, nếu nó nhận được một SIGQUIT khi in Z s, nó không in Q s mà đuổi theo. Thay vào đó, nó in chúng ra chỉ sau khi tôi chấm dứt thực hiện thủ công thông qua một KeyboardInterrupt. Tôi muốn các số Q s được in ngay sau Z s.

Điều này xảy ra khi sử dụng Python2.3.

Tôi đang làm gì sai? Muchas gracias.

#!/usr/bin/python 

from signal import * 
from time import sleep 
from sys import stdout 

def write(text): 
    stdout.write(text) 
    stdout.flush() 

def process_quit(signum, frame): 
    for i in range(10): 
     write("Q") 
     sleep(0.5) 

def process_tstp(signum, frame): 
    for i in range(10): 
     write("Z") 
     sleep(0.5) 

signal(SIGQUIT, process_quit) 
signal(SIGTSTP, process_tstp) 

while 1: 
    write('.') 
    sleep(0.5) 

Trả lời

6

Sự cố lớn hơn của bạn đang chặn trong trình xử lý tín hiệu.

Điều này thường không được khuyến khích vì điều này có thể dẫn đến các điều kiện thời gian lạ. Nhưng nó không hoàn toàn là nguyên nhân của vấn đề của bạn kể từ khi điều kiện thời gian bạn đang dễ bị tồn tại vì sự lựa chọn của bạn xử lý tín hiệu.

Dù sao, đây là cách ít nhất giảm thiểu điều kiện thời gian bằng cách chỉ đặt cờ trong trình xử lý của bạn và rời khỏi vòng lặp chính để thực hiện công việc thực tế. Giải thích cho lý do mã của bạn hoạt động lạ được mô tả sau mã.

#!/usr/bin/python 

from signal import * 
from time import sleep 
from sys import stdout 

print_Qs = 0 
print_Zs = 0 

def write(text): 
    stdout.write(text) 
    stdout.flush() 

def process_quit(signum, frame): 
    global print_Qs 
    print_Qs = 10 

def process_tstp(signum, frame): 
    global print_Zs 
    print_Zs = 10 

signal(SIGQUIT, process_quit) 
signal(SIGTSTP, process_tstp) 

while 1: 
    if print_Zs: 
     print_Zs -= 1 
     c = 'Z' 
    elif print_Qs: 
     print_Qs -= 1 
     c = 'Q' 
    else: 
     c = '.' 
    write(c) 
    sleep(0.5) 

Dù sao, đây là những gì đang diễn ra.

SIGTSTP đặc biệt hơn SIGQUIT.

SIGTSTP mặt nạ các tín hiệu khác đang được phân phối trong khi trình xử lý tín hiệu của nó đang chạy. Khi hạt nhân đi để cung cấp SIGQUIT và thấy rằng xử lý của SIGTSTP vẫn đang chạy, nó chỉ đơn giản là lưu nó cho sau này. Khi một tín hiệu khác đi qua để phân phối, chẳng hạn như SIGINT khi bạn CTRL + C (còn gọi là KeyboardInterrupt), hạt nhân nhớ rằng nó không bao giờ phân phối SIGQUIT và phân phối nó ngay bây giờ.

Bạn sẽ nhận thấy nếu bạn thay đổi while 1: thành trong vòng lặp chính và thực hiện lại trường hợp thử nghiệm, chương trình sẽ thoát mà không chạy trình xử lý SIGTSTP vì thoát không kích hoạt lại cơ chế phân phối tín hiệu của hạt nhân.

Chúc may mắn!

1

Trên Python 2.5.2 trên Linux 2.6.24, mã của bạn hoạt động chính xác như bạn mô tả kết quả mong muốn của bạn (nếu tín hiệu nhận được trong khi vẫn xử lý tín hiệu trước đó, tín hiệu mới được xử lý ngay sau khi tín hiệu đầu tiên kết thúc).

Trên Python 2.4.4 trên Linux 2.6.16, tôi thấy hành vi sự cố mà bạn mô tả.

Tôi không biết điều này là do sự thay đổi trong Python hoặc trong hạt nhân Linux.

Các vấn đề liên quan