2011-12-16 7 views
3

Iは、2つの異なるスレッドに分割されており、便宜上、(私は既存のコードを再利用しています)アプリケーションを有する:トリガイベント

  • つのスレッドがねじれリアクター
  • 別のスレッドに実行をインタラクティブメニューを実行する

私がインタラクティブメニューから実行したいことの1つは、リアクターとやり取りすることです。ユーザーが特定のコマンドを入力すると、ねじれイベントをトリガーしたいと思う。ここに私のコードの非常に単純化したバージョンです:あなたが見ることができるように

from twisted.spread     import pb 
from twisted.internet     import reactor 
import threading 

class TaskGatewaySupport(): 

    def __init__(self): 
     self.object = None 
     self.factory = pb.PBClientFactory() 
     self.connector = None 

    def gotObject(self, object): 
     print 'gotObject > %s' % object 
     self.object = object 
     return object 

    def gotData(self, data): 
     return data 

    def gotNoObject(self, reason): 
     print 'gotNoObject > no object: %s' % reason 

    def connect(self, task_gateway_host = '127.0.0.1', task_gateway_pb_port = 8889): 
     print 'Connecting to %s:%s' % (task_gateway_host, task_gateway_pb_port) 
     self.connector=reactor.connectTCP(task_gateway_host, task_gateway_pb_port, self.factory) 
     d = self.factory.getRootObject() 
     d.addCallbacks(self.gotObject, self.gotNoObject) 
     return d 

def Menu(task_gateway_support): 
    while True: 
     print ''' 

     A) Connect 

     ''' 
     choice = raw_input('Option > ') 
     if choice == 'A' : task_gateway_support.connect() 
     else    : print "ERR: command not yet supported" 

def version1(): 
    task_gateway_support = TaskGatewaySupport() 
    thread = threading.Thread(target = Menu, args = (task_gateway_support,)) 
    thread.start() 
    reactor.run() 

def version2(): 
    task_gateway_support = TaskGatewaySupport() 
    d = task_gateway_support.connect() 
    reactor.run() 

if __name__ == '__main__': 
    version1() 

が、私は2つの異なるバージョンを示しています:

  • VERSION1は、私が実行したいものですが、それは
  • ありません
  • バージョン2は、スレッドが1つしかありません、それはインタラクティブではありません

この結果得られますバージョン2を実行:

を0
Connecting to 127.0.0.1:8889 
gotObject > <twisted.spread.pb.RemoteReference instance at 0x88e734c> 

これは私が期待していたものです。バージョン1は、この与える実行

:私はここでやっている何

 A) Connect 


Option > A 
Connecting to 127.0.0.1:8889 


     A) Connect 


Option > ^CgotNoObject > no object: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectError'>: An error occurred while connecting: [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionLost'>: Connection to the other side was lost in a non-clean fashion: Connection lost. 
]. 
] 

は、オプションAを選択して、何も起こらないので、私はエラーメッセージを示し^ Cを押します。

私は2つの異なるスレッドでオブジェクトを共有しているので、問題が発生していると思うし、非ねじれスレッドからねじれイベントをトリガーしようとしています。私は、オブジェクトが共有されているので、原子炉はオブジェクトに何か酔っていることを知っていることを期待していました。

私の主な質問は、どのように私は別のスレッドからねじれイベントを引き起こすことができますか?

答えて

2

このためにスレッドを使用しないでください。 1つのスレッドでユーザー入力を受け入れる方法については、User interaction in twisted processを参照してください。

それ以外の非リアクタースレッドからTwisted APIを呼び出す場合は、いつでもreactor.callFromThreadを使用してください。

0

私は実際にTwistedでこの問題に直面しました。ありがたいことに、たくさんのグーグルで私はこの答えを考え出すことができました。実際にはうまくいきます! - そして、メインで

def my_function(s): 
    do_something_with_s 

class GetCommands(): 
def start(self, callable): 
    self.callable = callable 
    self.startReceiving() 

def startReceiving(self, s = ''): 
    self.callable(s) 
    if s != 'exit': 
     threads.deferToThread(raw_input,' >>> ').addCallback(self.startReceiving) 

-

getCmds = GetCommands() 
reactor.callWhenRunning(getCmds.start, my_function) 

reactor.listenTCP(PORT, factory) 
reactor.run() 
+0

ユーザー入力を取得するために問題の少ない方法を参照してくださいジャン・ポールの答え。この戦略には問題があります: 'raw_input'がスレッド内で実行されている場合、原子炉が稼動している間にそれを停止する安全な方法はありません。ユーザーが最後のコマンドを入力するまで待つ必要があります。 – Glyph

+0

あなたが正しいです、私は終了する前に最終的なコマンドを入力する必要があるというその問題にぶつかってきました。迷惑ですが、小さな問題です。私はあなたが結合メソッドのタイムアウトでスレッドを放棄することができると思うが、それはダクトテープの修正です。 – Milean

+0

Jean-Paulの答えは、Twistedに付属のstdioを使用しています。これはraw_input()を使用した回避策であり、Windowsでは動作しません。したがって、UNIXシステムでのみこれを実行しているなら、それは良い方法です。 – Milean

関連する問題