Reputation: 2770
I am building a GUI application for serial communication with a digital pump. I got stuck in the update mechanism used for fetching information from it. The update_values method is called every 5 seconds using a QTimer (From the PySide module), but the user can specifically order an update by calling the same method. For that reason I only want just one thread to run on the update_values code. However this doesn't seem to work using either a semaphore or a Lock as more than one thread enter the semaphore block at will:
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"
Upvotes: 2
Views: 1211
Reputation: 94951
Because you're using a non-blocking call to acquire
(by using acquire(blocking=False)
), you need to make sure you only continue on in the method if you actually acquired the semaphore, like this:
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()
This behavior is described in the documentation:
acquire([blocking])
When invoked without arguments: if the internal counter is larger than zero on entry, decrement it by one and return immediately. If it is zero on entry, block, waiting until some other thread has called release() to make it larger than zero. This is done with proper interlocking so that if multiple acquire() calls are blocked, release() will wake exactly one of them up. The implementation may pick one at random, so the order in which blocked threads are awakened should not be relied on. There is no return value in this case.
When invoked with blocking set to true, do the same thing as when called without arguments, and return true.
When invoked with blocking set to false, do not block. If a call without an argument would block, return false immediately; otherwise, do the same thing as when called without arguments, and return true.
Upvotes: 3