2016-09-15 64 views
2

編輯9/15/16:在我原來的代碼中(仍在下面發表)我試圖用.join()函數,這是一個愚蠢的錯誤,因爲它只能用於線程對象。我試圖 (1)連續運行一個線程獲取數據並將其保存到文件中 (2)有第二個線程或合併隊列,一旦用戶輸入標誌(即「停止」 )。它不會中斷數據收集/保存線程。(Python)用原始輸入停止線程?

我需要多線程幫助。我試圖運行兩個線程,一個處理數據,另一個檢查一個標誌來停止程序。

我通過反覆試驗瞭解到,如果我的電腦沒有爆炸,我無法打斷一個while循環。另外,我放棄了我的GUI代碼,因爲它讓我的代碼太複雜了多線程。

我想要做的是運行一個線程,從Arduino收集數據,將其保存到一個文件,並重復此操作。第二個線程將掃描標誌 - 可以是raw_input?我想不出任何用戶可以做什麼來停止數據採集程序。

我非常感謝這方面的幫助。這裏是我的代碼(其中很大一部分是僞代碼,你可以看到):

#threading 
import thread 
import time 

global flag 

def monitorData(): 
    print "running!" 
    time.sleep(5) 

def stopdata(flag): 

    flag = raw_input("enter stop: ") 

    if flag == "stop": 
     monitorData.join() 

flag = "start" 

thread.start_new_thread(monitorData,()) 
thread.start_new_thread(stopdata,(flag,)) 

我得到的錯誤是這樣的,當我嘗試在IDLE進入「停止」。

未處理異常線程通過 回溯(最近通話最後一個)開始: 文件 「C:\用戶\ otangu〜1 \應用程序數據\本地\ TEMP \ IDLE_rtmp_h_frd5」,第16行,在stopdata AttributeError的:'函數'對象沒有屬性'加入'

我再次非常感謝任何幫助,迄今爲止我已經教會了自己的Python,這是我碰到的第一道巨大的牆。

回答

0

這是不可能的。線程函數必須完成。你不能從外面加入它。

+0

'.join'是線程對象,而不是功能!我現在明白了。謝謝!:) – Liv

+0

是的,但線程對象來自不同的模塊。線程模塊不能連接線程。 – gavriel

0

您正在尋找這樣的事情:

from threading import Thread 
from time import sleep 

# "volatile" global shared by threads 
active = True 

def get_data(): 
    while active: 
     print "working!" 
     sleep(3) 

def wait_on_user(): 
    global active 
    raw_input("press enter to stop") 
    active = False   

th1 = Thread(target=get_data) 
th1.start() 
th2 = Thread(target=wait_on_user) 
th2.start() 

th1.join() 
th2.join() 

你犯了幾個明顯的,在你的代碼少一些明顯的錯誤。首先,在線程對象上調用連接,而不是函數。同樣,連接不會殺死一個線程,它會等待線程完成。一個線程在沒有更多代碼執行時結束。如果你想要一個線程運行直到某個標誌被設置,你通常在你的線程中包含一個循環來檢查每秒鐘左右的標誌(取決於你需要的時間精度)。

另外,穿線模塊優於下槓桿螺紋模塊。後者已經在python3中刪除。

+0

非常感謝!這是我犯的一個愚蠢的錯誤 - 我應該知道'join(),get()'等在線程對象而不是函數上被調用。 因此,隨着你提供的代碼,我將不得不實際擊中輸入或任何東西,除了「停止」爲'th1'繼續運行,是否正確?理想情況下,我想'th1'重複,直到用戶輸入一個標誌來停止它。 再次感謝您的時間和耐心 – Liv

+0

@Liv nope,th1將繼續全力以赴。它只會在你進入「停止」時停止。嘗試一下代碼,如果你什麼也不做,你應該看到每3秒打印一次「工作」。 –

+0

@我改變了我的答案,使其更加清晰。 'wait_on_user'中不需要'while'循環,這只是一個例子。 'th1'永遠不會停止等待'th2'它保持循環,它只檢查'active'是否已經改變(每個循環一次)。此檢查幾乎不需要時間,並且不會阻塞該線程。 –

1

您看到的錯誤是調用函數加入的結果。您需要在thread對象上調用join。您不捕獲對該線程的引用,因此無論如何您都無法撥打join。你應該像這樣join

th1 = thread.start_new_thread(monitorData,()) 

# later 
th1.join() 

至於解決方案,您可以使用Queue線程之間進行通信。隊列用於向工作線程發送退出消息,並且如果工作人員在隊列中沒有從隊列中拾取任何東西,它會運行從Arduino收集數據的代碼。

from threading import Thread 
from Queue import Queue, Empty 


def worker(q): 
    while True: 

     try: 
      item = q.get(block=True, timeout=1) 

      q.task_done() 
      if item == "quit": 
       print("got quit msg in thread") 
       break 

     except Empty: 
      print("empty, do some arduino stuff") 


def input_process(q): 
    while True: 
     x = raw_input("") 

     if x == 'q': 
      print("will quit") 
      q.put("quit") 
      break 

q = Queue() 
t = Thread(target=worker, args=(q,)) 
t.start() 

t2 = Thread(target=input_process, args=(q,)) 
t2.start() 

# waits for the `task_done` function to be called 
q.join() 

t2.join() 
t.join() 

它可能更多的代碼比你希望的,並具有檢測隊列異常是有點醜,但這不依賴於任何全局變量,將永遠退出及時爲空。對於基於sleep的解決方案,情況不會如此,在恢復執行之前,需要等待任何當前調用sleep才能完成。

正如其他人所指出的,你真的應該使用threading而不是早期的thread模塊還我會建議你使用Python 3學習,而不是Python 2

+0

一旦我完成了這個項目,我一定會轉移到Python3。我只是希望你提供一些澄清,謝謝!我的問題是試圖讓'worker()'函數持續運行,直到用戶輸入標誌。我應該在我原來的問題中更加清楚,理想情況下我不希望用戶每次都必須敲入回車才能運行arduino代碼。再次感謝您的幫助!我非常感謝你的耐心等待 – Liv

+0

你不需要繼續按下一個鍵就可以繼續探測arduino。嘗試運行它。 –