2010-08-17 5 views
7

트위스트에 대해 이해하는 것으로부터, 리액터 스레드에서 실행되는 것은 차단되어서는 안됩니다. 모든 블로킹 활동은 다른 스레드로 위임되어야하며 콜백이 완료되면 원자로 스레드로 되돌아갑니다.twisted + gtk : 스레드 또는 반응기 스레드에서 GUI 작업을 실행해야합니까?

이렇게하면 gtk 일에도 적용됩니까? 예를 들어 연결이 실패하면 "연결 실패"메시지를 표시하려고합니다. 어떻게해야합니까 :

def connectionFailed(self, reason): 
    dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, 
         buttons=gtk.BUTTONS_CLOSE, 
         message_format="Could not connect to server:\n%s" % (
          reason.getErrorMessage())) 
    dlg.run() 

나 :

def connectionFailed(self, reason): 
    dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, 
         buttons=gtk.BUTTONS_CLOSE, 
         message_format="Could not connect to server:\n%s" % (
          reason.getErrorMessage())) 
    reactor.callInThread(dlg.run) 

나 :

def connectionFailed(self, reason): 
    def bloogedy(): 
     dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, 
          buttons=gtk.BUTTONS_CLOSE, 
          message_format="Could not connect to server:\n%s" % (
           reason.getErrorMessage())) 
     dlg.run() 
    reactor.callInThread(bloogedy) 

?

편집 : 우 오케이, 후자의 두 사람은 정말 엉망이되었습니다. 그래서 나는 대답이 첫 번째라고 생각합니다. 그럼 내 질문은 : 왜? 이것은 원자로 실을 막는 것처럼 보입니다.

답변

10

문제는 실제로 스레드와 GUI와 관련이 없습니다. 같은 스레드에서 Twisted와 GTK를 항상 사용해야합니다. 달리 할 필요가 없습니다.

gtk.Dialog.run()을 사용하고있는 것이 문제입니다. 이것은 결코 사용해서는 안되는 Twisted API입니다. 재진입 메인 루프를 실행하면 현재 이벤트 핸들러가 차단되지만 다른 이벤트 핸들러는 한 레이어를 스택 아래로 실행할 수 있습니다. GTK는 재진입 메인 루프를 훌륭하게 지원하지만, Twisted는 그렇지 않습니다. (말했듯이, 사용하지 않아야합니다.)

MessageDialog.run은 스레드에서 작동하지 않으므로 실제로는 해당 옵션이 없습니다. 예기치 않은 동작으로 인해 응용 프로그램이 이상하게 작동하거나 중단 될 수 있습니다. GTK는 쓰레드를 잘 지원하지만, 아무 의미가 없기 때문에 결코 쓰레드를 사용하지 않아야하는 것들이 있습니다. 이것이 그 중 하나입니다.

아무런 처리도하지 않고 (사용자가 대화 상자의 버튼을 기다리는 것과 같이) 어떤 일이 일어날 때까지 기다리고 싶다면 Deferred을 반환하는 함수를 사용해야합니다 , 스레드가 아닙니다. 그렇게되면 gtk.Dialog은 응답 한 지점에서 신호를 내 보냅니다 : "response". 메시지를 대화 상자에 표시하는 매우 간단한 함수를 연결하고 완료되면 Deferred을 반환 할 수 있습니다. 여기에 예제가있다 :

def showMessage(text): 
    mdlg = gtk.MessageDialog(type=gtk.MESSAGE_INFO, 
          buttons=gtk.BUTTONS_CLOSE, 
          message_format=text) 
    result = Deferred() 
    def response(dialog, response_id): 
     mdlg.destroy() 
     result.callback(response_id) 
     return False 
    mdlg.connect("response", response) 
    mdlg.show_all() 
    return result 
+0

아에 시작하는 코드를 포함하도록 메시지를 편집했습니다. 나는 run()과 관련이 있다는 것을 암시했다. 지연은 확실히 방법입니다. – Claudiu

0

Gtk +를 사용한 경험에서 가장 좋은 방법은 별도의 스레드에서 GUI를 실행하는 것입니다. Gtk + 메인 루프 (idle_add 함수를 사용하여)에서 함수를 실행하여 GUI 쓰레드로 진행할 수 있습니다. 나는 원자로에 대해서 모른다. 그러나 당신의 예제에서 GUI와 같은 통신 방식이 가능할 것으로 보인다.

예,이 (죄송합니다, 나는 코드를 테스트하지 않았습니다)처럼 :

def connectionFailed(self, reason): 
    def frob(): 
     dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, 
          buttons=gtk.BUTTONS_CLOSE, 
          message_format="Could not connect to server:\n%s" % (
           reason.getErrorMessage())) 
     dlg.run() 
    gobject.idle_add(frob) 

(이 코드 외에, gtk.main가 자신의 스레드에서 실행해야합니다)

이를 Gtk + 스레드에서 frob 함수를 실행하고 반응기 스레드를 차단하지 않습니다.

이 별도의 스레드에서 GTK +를 시작합니다 : 당신은 몇 가지 복잡한 GUI 상호 작용을해야하는 경우

import threading 
import pygtk 
pygtk.require('2.0') 
import gtk 
import gobject 
def gtk_thread(): 
    gtk.main() 
threading.Thread(target=gtk_thread) 

, 당신은 continuation-passing style

편집를 사용하여 프로그래밍해야합니다은 : 별도의 GTK +를 실행하는 예를 추가 thread

+0

gui를 다른 스레드에서 어떻게 실행합니까? 방금'gtk2reactor.install()'을하고 그 원자로를 사용했습니다. 내가 트위스티드 + gtk를 사용하지 않고 시도했을 때 큰 문제가 발생했습니다. – Claudiu

+0

Gtk +를 별도의 스레드 인 –

0

권장 및 지원되지 않는 것은 아니지만, 트위스트 10.x를 함께 다음 코드는 gtk.main()를 사용하여 계속하는 것을 가능하게 할 것으로 보인다/dialog.run()

gobject.idle_add(lambda *x: reactor.runUntilCurrent()) 
    reactor.startRunning()  
    dialog.run() 
관련 문제