[Tutor] Changing instance attributes in different threads
Michael Lange
klappnase at freenet.de
Tue Feb 7 23:31:06 CET 2006
On Tue, 07 Feb 2006 06:02:45 -0500
Kent Johnson <kent37 at tds.net> wrote:
>
> One way to make this code thread-safe is to use a threading.Condition()
> instead of a boolean variable:
>
> thread 1 does:
>
> self.lock.acquire()
> if condition:
> self.name = 'bob'
> else:
> self.name = 'mike'
> self.lock.release()
>
> thread 2 does:
>
> self.lock.acquire()
> n = self.name
> self.lock.release()
> if n == 'bob':
> <do something>
> else:
> <do something else>
>
> If this is the only communication or synchronization between the two
> threads I don't think the lock is needed at all - thread 2 is presumably
> in a loop and thread 1 is controlling the behaviour of the loop
> asynchronously. If there is some other kind of synchronization between
> the loops, and thread 2 is only supposed to run once for each setting of
> self.name in thread 1, you could use Condition.wait() and
> Condition.notify() to do the synchronization.
>
Thanks Kent,
In fact I have three threads, a main gui thread and two child threads. Child thread 1 reads data
from the soundcard and appends these data to two lists which I use as recording buffer. The data from
list 1 are used by the gui thread to draw a vumeter, the data from list 2 are written to the
target file. So the communication between the threads occurs when the gui thread resp. child thread 2
read and empty the buffer lists to process the data.
So my functions currently (with boolean "locks") look like:
gui thread (this function is called periodically by Tkinter):
def get_peaks(self):
if self.vu_locked:
return None
self.vu_locked = 1
data = [x for x in self.vubuffer]
self.vubuffer = []
self.vu_locked = 0
if not data:
return None
left, right = 0, 0
for d in data:
left = max(audioop.max(audioop.tomono(d, 2, 1, 0), 2), left)
right = max(audioop.max(audioop.tomono(d, 2, 0, 1), 2), right)
return left, right
thread 1:
vubuffer = []
recbuffer = []
while self.running:
data = self._audioobj.read(self._fragsize)# read data from soundcard
vubuffer.append(data)
if not self.vu_locked:
self.vu_locked = 1
self.vubuffer += vubuffer
vubuffer = []
self.vu_locked = 0
if self.recording:
recbuffer.append(data)
if not self.rec_locked:
self.rec_locked = 1
self.recbuffer += recbuffer
recbuffer = []
self.rec_locked = 0
thread 2:
while self.recording:
# wait a moment until there is something in the buffer to be written
time.sleep(0.1)
if not self.rec_locked:
self.rec_locked = 1
data = [x for x in self.recbuffer]
self.recbuffer = []
self.rec_locked = 0
for d in data:
self._waveobj.writeframesraw(d)# write the data to a file
So I think I need two Condition objects here; it is most important here that thread 1 does not
block to minimize the risk of recording buffer overruns, but from reading the docs I am
not sure about the correct procedure. So if I change self.rec_locked and self.vu_locked from the
code above to be Condition objects is it correct to do:
thread 1:
vubuffer = []
recbuffer = []
while self.running:
data = self._audioobj.read(self._fragsize)# read data from soundcard
vubuffer.append(data)
if self.vu_locked.acquire(blocking=0):
self.vubuffer += vubuffer
vubuffer = []
self.vu_locked.release()
if self.recording:
recbuffer.append(data)
if self.rec_locked.acquire(blocking=0):
self.recbuffer += recbuffer
recbuffer = []
self.rec_locked.release()
thread 2:
while self.recording:
# wait a moment until there is something in the buffer to be written
time.sleep(0.1)
data = []
if self.rec_locked.acquire(blocking=0):
data = [x for x in self.recbuffer]
self.recbuffer = []
self.rec_locked.release()
for d in data:
self._waveobj.writeframesraw(d)# write the data to a file
Thanks
Michael
More information about the Tutor
mailing list