2016-09-02 17 views
0

私は数秒後にスレッドを停止することができる方法(内部)ターゲット関数の内部からスレッドを停止しますか?

t1 = Thread(target=call_script1, args=()) 
t2 = Thread(target=call_script2, args=()) 
t3 = Thread(target=call_script3, args=()) 

t1.start() 
t2.start() 
t3.start() 

t1.join() 
t2.join() 
t3.join() 

は、メインプログラムは、スレッドが戻るまで待つあります。私は方法があるかどうかを知りたい - 私はスレッドを生成する - t2と言うと、それは関数call_script2を対象とする。関数は完全に実行するのに5秒かかると言います。スレッドを3秒後に返すことができるかどうかを知りたい。

3秒後にスレッドが戻る能力は、call_script2関数内にある必要があります。メインスレッドでstop_event.wait(3)を実行しても動作しないと思います。

call_script2関数は次のようになります。

def InterfaceThread2(): 
    a = 1; 
    d = 2 
    i = 1 
    while i ==1: 
     #ser = serial.Serial(3, 115200) 
     if ser.isOpen(): 
      ser.write('\x5A\x03\x02\x00\x02\x07') 

      a = ser.read(7) #### THIS COMMAND WAITS UNTIL IT RECEIVES DATA FROM MCU 
      ## This usually happens in 100ms in theory. If it is taking like more than 100ms -for safety say I will wait for three seconds and if it did not respond back 
      ## I want to stop the thread and popup an error message. 

     # Tell the GUI about the Information 
     wx.CallAfter(pub.sendMessage, "APP_EVENT2", arg1 = a, arg2 = d) 
     print "hello" 

     time.sleep(1) 
     i = i+1 
+0

をするかどうか3秒後にスレッドを終了して終了させますか? – FamousJameous

+0

ターゲット関数call_script2 - MCUとのシリアル通信を呼び出します。 MCUは、読まれるように要求されたときに返信するのに100msかかる。 MCUが応答しなかった場合、スレッドを停止します。エラーメッセージをポップアップします。 –

+0

応答は、続行するか終了するかを制御しますか?応答の時から3秒まで何が起こるはずですか?これは 'call_script2'コードを投稿した方が簡単かもしれません。 – FamousJameous

答えて

1

serial.Serial()コンストラクタで利用可能なtimeoutパラメータを使用して、適切な動作を得ることができると思います。また、あなたは彼らがリード/ライトデータとして、あなたのスレッドがお互いを踏まないように、threading.Lock()Serialインスタンスとのやり取りを保護する必要があります:あなたが決めるんどのような条件で

ser = serial.Serial(..., timeout=3, ...) 
lock = Threading.Lock() 

def call_script1(): 
    a = 1 
    d = 2 
    i = 1 
    while i == 1: # Lock is acquired here 
     with lock: 
      if ser.isOpen(): 
       ser.write('\x5A\x03\x02\x00\x02\x07') 
       a = ser.read(7) 
       if len(a) != 7: 
        # We didn't get all the bytes we wanted, a timeout 
        # must have occurred. 
        print("Only read {} bytes!".format(len(a))) 
        # Maybe exit or throw an exception? 

     # Lock is released here. 
     # Tell the GUI about the Information 
     wx.CallAfter(pub.sendMessage, "APP_EVENT2", arg1 = a, arg2 = d) 
     print "hello" 

     time.sleep(1) 
     i = i+1 

def call_script2(): 
    while i == 1: 
     with lock: 
      if ser.isOpen(): 
       # Do whatever 

def call_script3(): 
    while i == 1: 
     with lock: 
      if ser.isOpen(): 
       # Do whatever 

t1 = Thread(target=call_script1, args=()) 
t2 = Thread(target=call_script2, args=()) 
t3 = Thread(target=call_script3, args=()) 

t1.start() 
t2.start() 
t3.start() 

t1.join() 
t2.join() 
t3.join() 
+0

私のプログラム内のこれらのcall_script関数の1つは、無限のwhileループです。ロックを取得した場合は解放しません –

+0

@JeshKundemループ内でロックを取得/解放することができます。 'call_script1()'が 'while i == 1:'の代わりに 'while True:'を使用したとします。それは、7バイト(または読み出しタイムアウト)の読み込みが終了した直後にロックを解放し、GUIを更新し、1秒間スリープした後、再度ロックを取得しようとします。 – dano

+0

私を教育してくれてありがとうございました。 –

0

Thread.join方法は任意timeoutパラメータを有しています。

# block until thread ``t`` completes, or just wait 3 seconds 
t.join(3) 

あなたはタイミングのこのロジックを処理するために、ターゲット機能を使用する場合は、私は3秒のタイムアウトに参加し、その後、新しいスレッドを生成呼び出しを行うためのラッパーを書くことをお勧めします。

from threading import Thread 
import time 

def counter(limit): 
    for i in range(limit): 
     print(i) 
     time.sleep(0.1) 

timeout = 3 
def wrapper(*args, **kwargs): 
    t = Thread(target=counter, args=args, kwargs=kwargs) 
    t.daemon = True 
    t.start() 
    t.join(timeout) 

t = Thread(target=wrapper, args=(100,)) 
t.start() 
t.join() 

メインプロセスが終了するまで、サブスレッドを実際に終了させないことに注意してください。内部で何が行われているかを知らずにスレッドを殺すと、あらゆる種類の混乱を招く可能性があります。

元の関数のコードを変更できる場合は、定期的にポーリングして、誰かが死んでもらいたいかどうかを確認することができます。

編集:私は幾分誤解されているように見えます。 PySerialを使用して1人のオープンワーカーSerialオブジェクトを3人のワーカーに共有する方法については、シリアルポートからの読み取り時にタイムアウトが必要でした。

+0

これは実際にスレッドをキャンセルするわけではありません。完了するまでブロッキングから 'join()'というスレッドを停止するだけです。 – dano

+0

良い点。それを ''デーモン ''スレッドにすることはできますが、メインプロセスが終了するまでは引き続き実行されます。 –