[Tutor] Changing instance attributes in different threads

Michael Lange klappnase at freenet.de
Wed Feb 8 19:11:25 CET 2006


On Wed, 08 Feb 2006 08:37:18 -0500
Kent Johnson <kent37 at tds.net> wrote:

> Another architecture you might consider is to have thread 1 put the 
> actual acquired buffers into two Queues that are read by the two 
> consumer threads. This would save you a lot of copying and give you a 
> cleaner implementation. It may block on the producer thread but the 
> Queue is locked only while something is actually being put in or taken 
> out so the blocks should be short.
> 
> For example (not tested!):
>      def get_peaks(self):
>          try:
>              data = self.vu_queue.get_nowait()
>          except Queue.Empty:
>              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:
> 
>          while self.running:
>              data = self._audioobj.read(self._fragsize)# read data from 
> soundcard
>              self.vu_queue.put(data)
>              self.rec_queue.put(data)
> 
> child thread 2:
> 
>          while self.recording:
>              data = self.rec_queue.get()
>              for d in data:
>                  self._waveobj.writeframesraw(d)# write data to file
> 

Thanks Kent,

the problem with Queues is that Queue.get() returns only one item at a time, but I found that depending
on cpu load and disk usage hundreds of data fragments may accumulate into the recording buffer, so in the "writer"
thread I would have to use something like (and similar in the get_peaks() method):

    while self.recording:
        data = []
        while not self.rec_queue.empty():
            try:
               data.append(self.rec_queue.get(block=0))
            except Queue.Empty:
               break
        for d in data:
            self._waveobj.writeframesraw(d)

I am not sure if this approach is more robust than the one that uses Condition() objects,
however I don't think the code looks cleaner.

> 
> > 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.
> 
> I don't understand your concern here.
> 

Maybe it is just because I have not fully understood how the Condition objects work; what I had in mind are
warnings like this one (from http://www.astro.washington.edu/owen/TkinterSummary.html):

    All Tkinter access must be from the main thread (or, more precisely, the thread that called mainloop).
    Violating this is likely to cause nasty and mysterious symptoms such as freezes or core dumps. Yes this
    makes combining multi-threading and Tkinter very difficult. The only fully safe technique I have found is polling
    (e.g. use after from the main loop to poll a threading Queue that your thread writes). I have seen it suggested
    that a thread can safely use event_create to communicate with the main thread, but have found this is not safe.

I guess I have to spend a second thought at this.

Thanks again

Michael




More information about the Tutor mailing list