2011-11-18 4 views
1

멀티 스레드 프로그램의 비동기 신호가 파이썬에서 올바르게 처리되지 않은 것 같습니다. 그러나 나는 누군가가 내가 어떤 원칙을 위반하거나 어떤 개념을 오해하고있는 곳을 발견 할 수 있는지 여기에서 확인할 것이라고 생각했다.비동기 키보드 인터럽트 및 멀티 스레딩

내가 여기에서 찾은 유사한 스레드가 있지만 아무 것도 그 것처럼 보이지 않습니다.

시나리오는 다음과 같습니다. 독자 스레드와 작성자 스레드 (기본 스레드)라는 두 개의 스레드가 있습니다. 작성기 스레드는 판독기 스레드가 폴링하는 파이프에 작성합니다. 두 스레드는 threading.Event() 프리미티브 (pthread_cond_wait을 사용하여 구현 된 것으로 가정)를 사용하여 조정됩니다. 주 스레드는 Event에서 기다리고 리더 스레드는 결국이를 설정합니다.

그러나 주 스레드가 Event에서 대기하는 동안 내 프로그램을 중단하려면 KeyboardInterrupt가 비동기 적으로 처리되지 않습니다. './bug.py'로 프로그램을 시작

#!/usr/bin/python 
import os 
import sys 
import select 
import time 
import threading 

pfd_r = -1 
pfd_w = -1 
reader_ready = threading.Event() 

class Reader(threading.Thread): 
    """Read data from pipe and echo to stdout.""" 
    def run(self): 
     global pfd_r 
     while True: 
      if select.select([pfd_r], [], [], 1)[0] == [pfd_r]: 
       output = os.read(pfd_r, 1000) 
       sys.stdout.write("R> '%s'\n" % output) 
       sys.stdout.flush() 
       # Suppose there is some long-running processing happening: 
       time.sleep(10) 
       reader_ready.set() 


# Set up pipe. 
(pfd_r, pfd_w) = os.pipe() 
rt = Reader() 
rt.daemon = True 
rt.start() 

while True: 
    reader_ready.clear() 
    user_input = raw_input("> ").strip() 
    written = os.write(pfd_w, user_input) 
    assert written == len(user_input) 
    # Wait for reply -- Try to ^C here and it won't work immediately. 
    reader_ready.wait() 

하고 프롬프트에서 어떤 입력을 입력 : 여기

내 지점을 설명하는 작은 프로그램입니다. 독자가 'R>'이라는 접두어로 회신하는 것을 확인하면 ^C을 사용하여 인터럽트를 시도하십시오.

내가 본 (우분투 리눅스 10.10, 파이썬 2.6.6)은 ^C이 블로킹 후 반환 될 때까지 처리되지 않는다는 것입니다. reader_ready.wait(). 예상했던대로 ^C이 비동기 적으로 발생하여 프로그램 종료가 발생합니다 (KeyboardInterrupt를 catch하지 않기 때문에).

이것은 인위적인 예제처럼 보일 수 있지만 실제로는 time.sleep(10)이 실제 계산으로 대체 된 실제 프로그램에서 실행 중입니다.

내가 예상 한 결과가 무엇인지 오해하는 것처럼 분명히 잘못하고 있습니다.

편집 : 나는 또한 Python 3.1.1로 테스트했는데 동일한 문제가 있습니다.

답변

1

threading._Eventwait() 방법은 실제로 thread.lockacquire() 방법에 의존합니다. 그러나 thread documentation은 잠금 장치의 acquire() 메서드를 인터럽트 할 수 없으며 모든 KeyboardInterrupt 예외는 잠금을 해제 한 후에 처리됩니다.

기본적으로 이것은 의도 한대로 작동합니다. 이 동작을 구현하는 스레딩 객체는 큐를 포함하여 특정 시점의 잠금에 의존하므로 다른 경로를 선택할 수도 있습니다.

+0

설명해 주셔서 감사합니다. 이 특정 "기능"이 사실 버그라는 주장을 할 수도 있습니다 ... 내 스레드를 동기화하는 또 다른 방법을 찾아야 할 것 같습니다.그렇게하기 위해 기본 내장 동기화 프리미티브를 사용할 수 없다는 것은 어리석은 것처럼 보입니다. –

+0

글쎄, 당신은 꽤 hackish 갈 수 있었다 :'while 1 :'(줄 바꿈)'if reader_ready.wait (1) : break' –

+0

나는 그것을 할 수 있거나'reader_ready.wait (99999)'를 타임 아웃으로 사용할 수있다. 가끔 sleep을하는 것처럼 보이기 때문에 키보드 인터럽트를 처리 할 수 ​​있습니다. 아직도, 해킹. –

0

또는 reader_ready.wait() 대신 signal 모듈의 pause() 기능을 사용할 수도 있습니다. signal.pause()은 블로킹 기능이며 프로세스가 신호를 수신하면 차단 해제됩니다. 귀하의 경우, ^C을 누르면 SIGINT 신호가 기능을 차단 해제합니다.

설명서에 따르면 Windows에서는이 기능을 사용할 수 없습니다. 나는 그것을 리눅스에서 테스트했고 작동한다. 시간 초과시 wait()을 사용하는 것보다 낫다고 생각합니다.