Preventing tread collisions

W

Wanderer

I have a program that has a main GUI and a camera. In the main GUI, you canmanipulate the images taken by the camera. You can also use the menu to check the camera's settings. Images are taken by the camera in a separate thread, so the long exposures don't block the GUI. I block conflicts between the camera snapshot thread and the main thread by setting a flag called self..cameraActive. I check to see if the cameraActive flag is false and set thecameraActive to True just before starting the thread. I generate an event on exiting the thread which sets the cameraActive flag to False. I also check and set and reset the flag in all the menu commands that access the camera. Like this.

def onProperties(self, event):
""" Display a message window with the camera properties
event -- The camera properties menu event
"""
# Update the temperature
if not self.cameraActive:
self.cameraActive = True
self.camera.getTemperature()
camDict = self.camera.getPropertyDict()
self.cameraActive = False
else:
camDict = {'Error': 'Camera Busy'}
dictMessage(camDict, 'Camera Properties')

This works but my question is, is there a better way using semaphores, locks or something else to prevent collisions between threads?

Thanks
 
D

Dave Angel

I have a program that has a main GUI and a camera. In the main GUI, you can manipulate the images taken by the camera. You can also use the menu to check the camera's settings. Images are taken by the camera in a separate thread, so the long exposures don't block the GUI. I block conflicts between the camera snapshot thread and the main thread by setting a flag called self.cameraActive. I check to see if the cameraActive flag is false and set the cameraActive to True just before starting the thread. I generate an event on exiting the thread which sets the cameraActive flag to False. I also check and set and reset the flag in all the menu commands that access the camera. Like this.

def onProperties(self, event):
""" Display a message window with the camera properties
event -- The camera properties menu event
"""
# Update the temperature
if not self.cameraActive:
self.cameraActive = True
self.camera.getTemperature()
camDict = self.camera.getPropertyDict()
self.cameraActive = False
else:
camDict = {'Error': 'Camera Busy'}
dictMessage(camDict, 'Camera Properties')

This works

I don't think so. in between the if and the assignment, another thread
could get in there and also set the flag. Then when either one of them
finishes, it'll clear the flag and the other code is unprotected.

For semaphores between multiple threads, you either have to define only
a single thread at any given moment being permitted to modify it, or you
have to use lower-level primitives, sometimes called test+set operation.

i don't know the "right" way to do this in Python, but this isn't it.
 
M

MRAB

I have a program that has a main GUI and a camera. In the main GUI, you can manipulate the images taken by the camera. You can also use the menu to check the camera's settings. Images are taken by the camera in a separate thread, so the long exposures don't block the GUI. I block conflicts between the camera snapshot thread and the main thread by setting a flag called self.cameraActive. I check to see if the cameraActive flag is false and set the cameraActive to True just before starting the thread. I generate an event on exiting the thread which sets the cameraActive flag to False. I also check and set and reset the flag in all the menu commands that access the camera. Like this.

def onProperties(self, event):
""" Display a message window with the camera properties
event -- The camera properties menu event
"""
# Update the temperature
if not self.cameraActive:
self.cameraActive = True
self.camera.getTemperature()
camDict = self.camera.getPropertyDict()
self.cameraActive = False
else:
camDict = {'Error': 'Camera Busy'}
dictMessage(camDict, 'Camera Properties')

This works but my question is, is there a better way using semaphores, locks or something else to prevent collisions between threads?
That suffers from a race condition in that self.cameraActive might be
False when it's checked in the 'if' condition but set to True just
afterwards by the other thread.

You could try a non-blocking semaphore:

def __init__(self):
self.cameraActive = Semaphore()

def onProperties(self, event):
""" Display a message window with the camera properties
event -- The camera properties menu event
"""
# Update the temperature
if self.cameraActive.acquire(False): # Non-blocking
# Successfully acquired the semaphore, so the camera wasn't active
self.camera.getTemperature()
camDict = self.camera.getPropertyDict()
self.cameraActive.release()
else:
camDict = {'Error': 'Camera Busy'}
 
A

Alexander Blinne

Am 12.12.2012 21:29, schrieb Dave Angel:
I don't think so. in between the if and the assignment, another thread
could get in there and also set the flag. Then when either one of them
finishes, it'll clear the flag and the other code is unprotected.

I have a general question about this kinds of things. I see that the
above is a common use case for some kind of lock which does this
testing/locking atomically. But the question is: if I know for sure that
there is no other thread that might get in the way this solution would
be fine, right?

In one of my applications i have a somewhat different case: i have a
list of objects and call the same method of each object, each in its own
thread (which is created and later joined just for this purpose). The
objects are thus only used by that one thread, the main thread waits for
all threads to be finished before accessing those objects again. Do i
really need some kind of locking for those objects?

Greetings
 
A

Andrew Robinson

if you already have the cameraActive variable reset by an event at
thread termination; it's not necessary to set it false in the menu
command. It's better NOT to do that. Your GUI menu functions need only
test to see if self.cameraActive is false, and then set it to true just
before the launch of the second thread. The second thread, itself,
ought never change the cameraActive variable.

I'm also not sure why you are able to obtain the information from the
camera sequentially (camDict?) when you say you are not blocking the GUI.
I assume self.camera.getTemperature() launches the second thread ? Is it,
somehow, explicitly allowing the continued processing of GUI events that
accessing the camera straight in the GUI would not allow?

If you are talking about the Python semaphore library, I don't think you
need it.

Semaphores are really for use when multiple threads wish to access a
resource where more than one thread can use the resource at a time;
That would mean multiple threads using the camera at once... not a good
idea.

The Lock() object essentially does the same thing, but assumes only 1
thread may use it at a time; hence that would be sufficient (if it
were needed at all!).

A lock is in the "thread" library (Python 2.xx) or the "threading"
library (Python 3.xx). Semaphores aren't part of the thread library in
Python 2.xx... (another reason not to bother with them...)

However, Locking will cause the GUI thread to block when the camera is
in use, which isn't what you want -- correct?

There is a way to test the lock but not block, which is equivalent to
your variable (to be honest!); I'm pretty sure that Python doesn't use
true Posix threads but only the GNU Pth library. That means that the
only time threads truly switch is determined by the Python interpreter.
In that case, all python variable assignments are going to be effectively
atomic anyhow... and a variable, like you are using, is identical to a lock.
(Atomic merely means the write can't be interrupted by a thread switch partway
through).

If you have a multi-processing environment, there is a multiprocessor
library -- where the lock or semaphore mechanism would be important.
But I really don't think you need it.
 
I

Ian Kelly

I have a general question about this kinds of things. I see that the
above is a common use case for some kind of lock which does this
testing/locking atomically. But the question is: if I know for sure that
there is no other thread that might get in the way this solution would
be fine, right?

If you know for sure that there is no other thread, then there is no
need for the flag in the first place.
In one of my applications i have a somewhat different case: i have a
list of objects and call the same method of each object, each in its own
thread (which is created and later joined just for this purpose). The
objects are thus only used by that one thread, the main thread waits for
all threads to be finished before accessing those objects again. Do i
really need some kind of locking for those objects?

No, if a resource is only ever used by one thread/process, then there
is no reason to lock it.
 
W

Wanderer

That suffers from a race condition in that self.cameraActive might be

False when it's checked in the 'if' condition but set to True just

afterwards by the other thread.



You could try a non-blocking semaphore:



def __init__(self):

self.cameraActive = Semaphore()



def onProperties(self, event):

""" Display a message window with the camera properties

event -- The camera properties menu event

"""

# Update the temperature

if self.cameraActive.acquire(False): # Non-blocking

# Successfully acquired the semaphore, so the camera wasn't active

self.camera.getTemperature()

camDict = self.camera.getPropertyDict()

self.cameraActive.release()

else:

camDict = {'Error': 'Camera Busy'}

Thanks. Why Non-blocking?
 
W

Wanderer

That suffers from a race condition in that self.cameraActive might be

False when it's checked in the 'if' condition but set to True just

afterwards by the other thread.



You could try a non-blocking semaphore:



def __init__(self):

self.cameraActive = Semaphore()



def onProperties(self, event):

""" Display a message window with the camera properties

event -- The camera properties menu event

"""

# Update the temperature

if self.cameraActive.acquire(False): # Non-blocking

# Successfully acquired the semaphore, so the camera wasn't active

self.camera.getTemperature()

camDict = self.camera.getPropertyDict()

self.cameraActive.release()

else:

camDict = {'Error': 'Camera Busy'}

Thanks. Why Non-blocking?
 
D

Dave Angel

<snip>

Thanks. Why Non-blocking?

You said you didn't want the GUI to lock up. Non-blocking lets you
choose alternative action when you would otherwise have to wait for the
resource.
 
W

Wanderer

You said you didn't want the GUI to lock up. Non-blocking lets you

choose alternative action when you would otherwise have to wait for the

resource.







--



DaveA

Thanks. I understand now.
 
W

Wanderer

You said you didn't want the GUI to lock up. Non-blocking lets you

choose alternative action when you would otherwise have to wait for the

resource.







--



DaveA

Thanks. I understand now.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,815
Latest member
treekmostly22

Latest Threads

Top