2010-07-12 24 views
13

Tập lệnh python của tôi chặn tín hiệu SIGINT bằng tín hiệu quy trình mô-đun để ngăn chặn thoát sớm, nhưng tín hiệu này được chuyển đến một tiến trình con mà tôi mở bằng Popen. là có một số cách để ngăn chặn đi qua tín hiệu này để các subprocess để nó cũng không phải là exited sớm khi người dùng nhấn ctrl-c?Làm thế nào để dừng SIGINT được chuyển đến subprocess trong python?

+0

Bạn đang sử dụng nền tảng nào? – ChristopheD

+0

Tôi đang sử dụng Ubuntu linux. – shino

Trả lời

2

Bạn có thể gán lại vai trò của ctrl-c bằng cách sử dụng mô-đun tty, cho phép bạn thao tác chuyển nhượng tín hiệu. Tuy nhiên, hãy cảnh báo rằng trừ khi bạn đặt chúng trở lại cách chúng trước khi bạn sửa đổi chúng, chúng sẽ tiếp tục tồn tại trong toàn bộ phiên của trình bao, ngay cả sau khi chương trình thoát. Dưới đây là một đoạn mã đơn giản để giúp bạn bắt đầu lưu trữ các cài đặt tty cũ của bạn, gán lại ctrl-c thành ctrl-x và sau đó khôi phục các cài đặt tty trước đó của bạn khi thoát.

import sys 
import tty 

# Back up previous tty settings 
stdin_fileno = sys.stdin.fileno() 
old_ttyattr = tty.tcgetattr(stdin_fileno) 

try: 
    print 'Reassigning ctrl-c to ctrl-x' 

    # Enter raw mode on local tty 
    tty.setraw(stdin_fileno) 
    raw_ta = tty.tcgetattr(stdin_fileno) 
    raw_ta[tty.LFLAG] |= tty.ISIG 
    raw_ta[tty.OFLAG] |= tty.OPOST | tty.ONLCR 

    # ^X is the new ^C, set this to 0 to disable it entirely 
    raw_ta[tty.CC][tty.VINTR] = '\x18' 

    # Set raw tty as active tty 
    tty.tcsetattr(stdin_fileno, tty.TCSANOW, raw_ta) 

    # Dummy program loop 
    import time 
    for _ in range(5): 
     print 'doing stuff' 
     time.sleep(1) 

finally: 
    print 'Resetting ctrl-c' 
    # Restore previous tty no matter what 
    tty.tcsetattr(stdin_fileno, tty.TCSANOW, old_ttyattr) 
14

xử lý tín hiệu được thừa kế khi bạn bắt đầu một tiến trình con, vì vậy nếu bạn sử dụng các module tín hiệu bỏ qua SIGINT (signal.signal(signal.SIGINT, signal.SIG_IGN)), sau đó tiến trình con của bạn tự động sẽ còn.

Có hai cảnh báo quan trọng, mặc dù:

  • Bạn phải thiết lập lờ handler trước bạn đẻ trứng quá trình con
  • Tuỳ chỉnh xử lý tín hiệu được đặt lại vào xử lý mặc định, kể từ khi quá trình con sẽ không có quyền truy cập vào mã trình xử lý để chạy nó.

Vì vậy, nếu bạn cần tùy chỉnh việc xử lý SIGINT thay vì bỏ qua, bạn có thể tạm thời bỏ qua SIGINT trong khi bạn sinh ra quá trình con, sau đó đặt lại trình xử lý tín hiệu tùy chỉnh của bạn.

Nếu bạn đang cố gắng nắm bắt SIGINT và đặt cờ để bạn có thể thoát ra tại điểm an toàn thay vì ngay lập tức, hãy nhớ rằng khi bạn đến điểm an toàn đó, mã của bạn sẽ phải dọn sạch con cháu của nó theo cách thủ công. quá trình con và bất kỳ quá trình nào nó bắt đầu sẽ bỏ qua SIGINT.

+0

Nếu điều này hoạt động (mà nó sẽ không luôn luôn), nó là một lựa chọn tốt hơn so với mucking với thiết bị đầu cuối. – zwol

+0

Nếu sử dụng fork()/exec() thay vì popen(), bạn có thể thực hiện SIG_IGN sau fork() trước exec(). Điều đó tránh tạm thời vô hiệu hóa trình xử lý trong phụ huynh. Có vẻ như sẽ có điều kiện chạy đua bất kể bạn làm gì, nhưng cách ngã ba()/exec() có vẻ an toàn hơn một chút. Tất nhiên, OP đã hỏi về Popen của python, nhưng câu hỏi này thực sự có vẻ là về Posix; đó là lý do tôi đến đây. – thejoshwolfe

+1

@thejoshwolfe: Để tránh điều kiện chạy đua, bạn sử dụng sigprocmask() để trì hoãn tín hiệu, đặt bộ điều khiển, ngã ba, đặt bộ điều khiển trở lại và sau đó sử dụng lại sigprocmask để bật lại tín hiệu. (Và nếu có bất kỳ tín hiệu nào đến giữa các lệnh gọi tới sigprocmask, chúng sẽ được phân phối tại thời điểm này.) –

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