2010-09-24 33 views
40

Tôi đang chạy mã này của tôi rất đơn giản:luồng lờ KeyboardInterrupt ngoại lệ

import threading, time 

class reqthread (threading.Thread): 
    def __init__ (self): 
    threading.Thread.__init__(self) 

    def run (self): 
    for i in range(0,10): 
     time.sleep(1) 
     print '.' 

try: 
    thread=reqthread() 
    thread.start() 
except (KeyboardInterrupt, SystemExit): 
    print '\n! Received keyboard interrupt, quitting threads.\n' 

Nhưng khi tôi chạy nó, nó in

$ python prova.py 
` 
. 
. 
^C. 
. 
. 
. 
. 
. 
. 
. 
Exception KeyboardInterrupt in <module 'threading' from '/usr/lib/python2.6/threading.pyc'> ignored 
` 

Trong thực tế python chủ đề phớt lờ tôi Ctrl +C ngắt bàn phím và không in Received Keyboard Interrupt. Tại sao? Có gì sai với mã này?

Trả lời

50

Hãy thử

try: 
    thread=reqthread() 
    thread.daemon=True 
    thread.start() 
    while True: time.sleep(100) 
except (KeyboardInterrupt, SystemExit): 
    print '\n! Received keyboard interrupt, quitting threads.\n' 

Nếu không có cuộc gọi đến time.sleep, quá trình chính là nhảy ra khỏi khối try...except quá sớm, vì vậy KeyboardInterrupt không được bắt. Suy nghĩ đầu tiên của tôi là sử dụng thread.join, nhưng điều đó dường như chặn quá trình chính (bỏ qua KeyboardInterrupt) cho đến khi thread hoàn tất.

thread.daemon=True làm cho luồng kết thúc khi quá trình chính kết thúc.

+4

Tôi tin rằng một thời gian chờ trên 'tham gia', tức là' trong khi thread.isAlive: thread.join (5) 'cũng sẽ hoạt động để duy trì luồng chính đáp ứng các ngoại lệ. –

+11

'thread.daemon = True' thực sự không được khuyến nghị vì nó không cho phép xóa sạch bất kỳ tài nguyên nào ... –

7

Để tóm tắt những thay đổi được đề nghị trong thecomments, các công việc sau tốt cho tôi:

try: 
    thread = reqthread() 
    thread.start() 
    while thread.isAlive(): 
    thread.join(1) # not sure if there is an appreciable cost to this. 
except (KeyboardInterrupt, SystemExit): 
    print '\n! Received keyboard interrupt, quitting threads.\n' 
    sys.exit() 
+0

Đang gọi" thread.join() "hơn và hơn trong" trong khi thread.isAlive(): "một điều tốt/có quan trọng không? – DevPlayer

+0

Cá nhân tôi không biết; có thể có giá trị cố gắng để tạo ra một điểm chuẩn nếu perf quan trọng với bạn cho điều đó? – rattray

+1

Lưu ý rằng lối ra() và sys.exit() không giống nhau. Bạn nên sử dụng sys.exit(). – DevPlayer

0

của tôi (hacky) giải pháp là khỉ-vá Thread.join() như thế này:

def initThreadJoinHack(): 
    import threading, thread 
    mainThread = threading.currentThread() 
    assert isinstance(mainThread, threading._MainThread) 
    mainThreadId = thread.get_ident() 
    join_orig = threading.Thread.join 
    def join_hacked(threadObj, timeout=None): 
    """ 
    :type threadObj: threading.Thread 
    :type timeout: float|None 
    """ 
    if timeout is None and thread.get_ident() == mainThreadId: 
     # This is a HACK for Thread.join() if we are in the main thread. 
     # In that case, a Thread.join(timeout=None) would hang and even not respond to signals 
     # because signals will get delivered to other threads and Python would forward 
     # them for delayed handling to the main thread which hangs. 
     # See CPython signalmodule.c. 
     # Currently the best solution I can think of: 
     while threadObj.isAlive(): 
     join_orig(threadObj, timeout=0.1) 
    else: 
     # In all other cases, we can use the original. 
     join_orig(threadObj, timeout=timeout) 
    threading.Thread.join = join_hacked 
2

sửa đổi nhẹ về giải pháp của ubuntu.

Loại bỏ tread.daemon = True theo đề nghị của Eric và thay thế các vòng lặp ngủ bởi signal.pause():

import signal 
try: 
    thread=reqthread() 
    thread.start() 
    signal.pause() # instead of: while True: time.sleep(100) 
except (KeyboardInterrupt, SystemExit): 
    print '\n! Received keyboard interrupt, quitting threads.\n' 
+1

Rất tiếc - nhưng tiếc là không được hỗ trợ trên Windows –

0

Đưa try ... except trong mỗi chủ đề và cũng là một trong signal.pause()đúngmain() công trình cho tôi.

Xem trước cho import lock. Tôi đoán đây là lý do tại sao Python không giải quyết ctrl-C theo mặc định.

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