Ctrl-C로 Python 스크립트를 종료 할 수 없습니다.


117

다음 스크립트로 Python 스레딩을 테스트하고 있습니다.

import threading

class FirstThread (threading.Thread):
    def run (self):
        while True:
            print 'first'

class SecondThread (threading.Thread):
    def run (self):
        while True:
            print 'second'

FirstThread().start()
SecondThread().start()

이것은 Kubuntu 11.10의 Python 2.7에서 실행됩니다. Ctrl+ C는 그것을 죽이지 않을 것입니다. 또한 시스템 신호 처리기를 추가하려고 시도했지만 도움이되지 않았습니다.

import signal 
import sys
def signal_handler(signal, frame):
    sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)

프로세스를 죽이기 위해 나는 프로그램을 Ctrl+로 백그라운드로 보낸 후 PID로 죽이고 Z있는데, 무시되지 않습니다. Ctrl+ C가 왜 그렇게 지속적으로 무시되고 있습니까? 어떻게 해결할 수 있습니까?


@dotancohen Windows에서 작동합니까?
kiriloff

@vitaibian : Windows에서 테스트하지 않았지만 OS와 관련이없는 것 같습니다.
dotancohen

답변:


178

Ctrl+ C는 주 스레드를 종료하지만 스레드가 데몬 모드가 아니기 때문에 계속 실행되고 프로세스가 계속 유지됩니다. 데몬으로 만들 수 있습니다.

f = FirstThread()
f.daemon = True
f.start()
s = SecondThread()
s.daemon = True
s.start()

그러나 또 다른 문제가 있습니다. 일단 메인 스레드가 스레드를 시작하면 다른 작업이 수행되지 않습니다. 그래서 그것은 종료되고 스레드는 즉시 파괴됩니다. 따라서 메인 스레드를 유지합시다.

import time
while True:
    time.sleep(1)

이제 Ctrl+ 를 누를 때까지 '첫 번째'와 '두 번째'를 계속 인쇄 C합니다.

편집 : 주석가가 지적했듯이 데몬 스레드는 임시 파일과 같은 것을 정리할 기회를 얻지 못할 수 있습니다. 필요한 경우 KeyboardInterrupt메인 스레드에서 를 잡아서 정리 및 종료를 조정하십시오. 그러나 많은 경우 데몬 스레드를 갑자기 죽게하는 것으로 충분할 것입니다.


6
이렇게하면 스레드가 정상적으로 중지되지 않고 일부 리소스가 해제되지 않는다는 점을 언급해야합니다.
Tommaso Barbugli

1
음, Ctrl-C는 어떤 것도 멈추는 우아한 방법이 아닙니다. 어떤 리소스가 남을지 잘 모르겠습니다. 프로세스가 종료 될 때 OS가 아무것도 회수하지 않아야합니까?
Thomas K

7
@ThomasK tempfile.TemporaryFile()예를 들어에서 만든 임시 파일이 디스크에 남아있을 수 있습니다.
Feuermurmel

1
@ deed02392 : 메인 스레드에 어떤 일이 발생하는지 정확히 알지 못하지만 종료 후 아무것도 할 수 없다는 것을 알고 있습니다. 데몬이 아닌 모든 스레드가 완료되면 프로세스가 완료됩니다. 부모-자녀 관계는 그것에 오지 않습니다.
Thomas K

4
python3에서처럼 보이는 당신이 전달할 수daemon=TrueThread.__init__
라이언 이닝


3

스레드가 죽을 것으로 예상 할 때 스레드에서 join ()을 호출하는 것이 가장 좋습니다. 루프를 끝내기 위해 코드를 자유롭게 사용했습니다 (청소가 필요한 모든 것을 거기에 추가 할 수도 있습니다). 변수 die는 각 패스에서 진실을 확인하고 True이면 프로그램이 종료됩니다.

import threading
import time

class MyThread (threading.Thread):
    die = False
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name

    def run (self):
        while not self.die:
            time.sleep(1)
            print (self.name)

    def join(self):
        self.die = True
        super().join()

if __name__ == '__main__':
    f = MyThread('first')
    f.start()
    s = MyThread('second')
    s.start()
    try:
        while True:
            time.sleep(2)
    except KeyboardInterrupt:
        f.join()
        s.join()

while True어리석은 일입니다. join직접 해야 합니다. 재정의 된 기능은 다소 의심 스럽습니다. 어쩌면 def join(self, force=False): if force: self.die = True그래서 join()에 의해 변경되지 않습니다 join(force=True)명 그들. 그러나 그럼에도 불구하고 중 하나를 결합하기 전에 스레드에 모두 알리는 것이 좋습니다 .
o11c

0

@Thomas K의 답변의 개선 된 버전 :

  • 이 요점is_any_thread_alive() 에 따라 어시스턴트 기능을 정의하면 자동으로 종료 될 수 있습니다 .main()

예제 코드 :

import threading

def job1():
    ...

def job2():
    ...

def is_any_thread_alive(threads):
    return True in [t.is_alive() for t in threads]

if __name__ == "__main__":
    ...
    t1 = threading.Thread(target=job1,daemon=True)
    t2 = threading.Thread(target=job2,daemon=True)
    t1.start()
    t2.start()

    while is_any_thread_alive([t1,t2]):
        time.sleep(0)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.