2014-06-10 96 views
1

我正在構建一個用於與數字泵進行串行通信的GUI應用程序。我陷入了用於從中獲取信息的更新機制。使用QTimer(來自PySide模塊)每5秒調用一次update_values方法,但用戶可以通過調用相同的方法專門訂購更新。出於這個原因,我只想要一個線程在update_values代碼上運行。然而,這似乎並沒有使用一個信號或鎖定爲多個線程隨意進入信號量塊的工作:線程應用程序的信號量同步失敗,Python

self.update_sema = threading.Semaphore(value=1) 

... ...

def update_values(self, initialize = False): 
    """This is the parameters update method.""" 

    self.update_sema.acquire(False) 
    print "ENTERED THE SEMAPHORE" 
    self.update_thread = threading.Thread(\ 
      target = self.actual_update_method,\ 
      args = (initialize,)) 
    self.update_thread.start() 
def actual_update_method(self, initialize): 

    # reading info mechanism 
    self.status["absolute_pos"] = self.send_Command('?', 10)[3:] 
    self.status["actual_pos"] = self.send_Command('?4', 10)[3:] 
    self.status["starting_vel"] = self.send_Command('?1', 10)[3:] 
    self.status["top_vel"] = self.send_Command('?2', 10)[3:] 
    self.status["cutoff_vel"] = self.send_Command('?3', 10)[3:] 
    self.status["backlash_steps"] = self.send_Command('?12', 10)[3:] 
    self.status["fluid_sensor"] = self.send_Command('?22', 10)[3:] 
    self.status["buffer_status"] = self.send_Command('?F', 10)[3:] 

    # These must be asked only once, at the initialization phase 
    if initialize: 
     #print "version set as well!" 
     self.status["version"] = self.send_Command('?&', 10)[3:] 
     self.status["checksum"] = self.send_Command('?#', 10)[3:] 

    self.update_sema.release() 
    print "EXITED THE SEMAPHORE" 

回答

2

因爲你「再使用非阻塞調用acquire(通過使用acquire(blocking=False)),你需要確保你只能繼續在該方法中,如果你真的收購了信號,就像這樣:

def update_values(self, initialize = False): 
    """This is the parameters update method.""" 

    if self.update_sema.acquire(False): 
     print "ENTERED THE SEMAPHORE" 
     self.update_thread = threading.Thread(\ 
       target = self.actual_update_method,\ 
       args = (initialize,)) 
     self.update_thread.start() 

此行爲在documentation描述:

獲取([阻斷])

當不帶參數調用:如果內部計數器是對條目大於 零,減一,並立即返回。如果它是 零進入,塊,等待,直到其他線程調用 release()使其大於零。這是通過適當的 聯鎖來完成的,這樣如果多個acquire()調用被阻塞,release()將會正好喚醒其中的一個。實現可能會在 中隨機選取一個,因此不應該依賴被阻塞的線程被喚醒的順序 。在這種情況下沒有返回值。

當使用阻塞設置爲true調用時,請執行與調用 時沒有參數相同的操作,並返回true。

當調用阻塞設置爲false時,不要阻塞。如果沒有參數的呼叫 會阻塞,立即返回false;否則, 與沒有參數時調用相同,並返回true。

+0

哇! 東西這麼簡單,但很麻煩... 但我仍然不明白。正如你上面所說的「當調用阻塞設置爲false時,不要阻塞」。這不意味着如果一個線程發現鎖定的信號量,那麼它應該在update_sema.release()之後的臨界區之後運行下一行。 – bergercookie

+0

@buttercookie不是,它只是表示'acquire'將返回'False'並繼續到代碼中的下一行。沒有可靠的方法讓代碼跳到釋放信號量的地方。拿你的例子來說,信號量是在一個完全不同的線程中發佈的。該程序不能跳到該行,因爲如果它不能獲取信號量,則不允許創建開頭的線程。如果'acquire'調用返回'False',那麼你有正確的邏輯將程序發送到任何你認爲「正確的地方」。 – dano