[Tutor] Changing instance attributes in different threads

Michael Lange klappnase at freenet.de
Wed Feb 8 12:17:33 CET 2006


On Tue, 7 Feb 2006 23:31:06 +0100
Michael Lange <klappnase at freenet.de> wrote:

> 
> 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:
> 
<snip>

Ok, some testing gave me the answer, with the code I posted I got an AssertionError, so obviously
the release() call has to be inside the "if self.rec_lock.acquire(blocking=0):" block.
So now my functions look like:

gui thread (periodically called by Tkinter):

    def get_peaks(self):
        if not self.vu_lock.acquire(blocking=0):
            return None
        data = [x for x in self.vubuffer]
        self.vubuffer = []
        self.vu_lock.release()
        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
   
child thread 1:

        vubuffer = []
        recbuffer = []
        while self.running:
            data = self._audioobj.read(self._fragsize)# read data from soundcard
            vubuffer.append(data)
            if self.vu_lock.acquire(blocking=0):
                self.vubuffer += vubuffer
                vubuffer = []
                self.vu_lock.release()
            if self.recording:
                recbuffer.append(data)
                if self.rec_lock.acquire(blocking=0):
                    self.recbuffer += recbuffer
                    recbuffer = []
                    self.rec_lock.release()

child thread 2:

        while self.recording:
            # wait a moment until there is something in the buffer to be written
            data = []
            time.sleep(0.1)
            if self.rec_lock.acquire(blocking=0):
                data = [x for x in self.recbuffer]
                self.recbuffer = []
                self.rec_lock.release()
            for d in data:
                self._waveobj.writeframesraw(d)# write data to file

This *seems* to work, however it looks like this code does not separate properly the gui from the child
threads which everyone says should be avoided in any case.
On the other hand, with the technique I used before, with a boolean as "lock", like:

             if not self.vu_locked:
                self.vu_locked = 1
                self.vubuffer += vubuffer
                vubuffer = []
                self.vu_locked = 0

it seems like the worst case is that both the gui and the child thread pass the test "if not self.vu_locked" at
the same time which might cause some data to be lost from the vubuffer list; probably that is something
I could live with.
So now my question:
Does anyone know how a threading.Condition() object is handled internally, so maybe its methods actually
can be called safely from the gui thread?

Thanks

Michael


More information about the Tutor mailing list