[linux-audio-dev] Re: mutex madness

New Message Reply About this list Date view Thread view Subject view Author view Other groups

Subject: [linux-audio-dev] Re: mutex madness
From: Paul Barton-Davis (pbd_AT_Op.Net)
Date: ke syys   29 1999 - 18:36:31 EDT


>Indeed. pthread mutexes aren't `fair'. If the ui gets 500 events
>behind it's entirely possible it will hog the mutex as it wraps a lock
>around each pop while the dsp is trying to push one event.
>
>However, if you build a fair mutex from pthread mutexes and condition
>variables, wouldn't the mutex-protected-queue approach be reliable?

well, in general, my code for handling mutex-protected queues looks
like the fairly "standard" thing:

     lock_queue ();
     while (queue_not_empty()) {
          entry = pop_first_entry ();
          unlock_queue ();

          process_entry (entry);
          lock_queue ();
     }
     unlock_queue ();

this at least leaves the queue unlocked during the time-consuming part
of things. typically, process_entry() for the UI thread involves at
least one expensive X protocol call, so in general, the DSP will get a
chance to grab the mutex.

things can more unpredictable, however, if you add one more runnable
thread to the entire OS thread list. if this thread gets to run
instead of the UI thread while the UI thread still holds the lock on
the queue, then the DSP thread is out of luck, and so are we. this is
even more likely (to the extent that it *is* likely at all) if the
input thread is has RT scheduling.

so, the above scheme will work most of the time, but still can't
guarantee that the dsp will get the lock when it needs to. even
turning the mutex into a "fair" one won't help this pathological
condition.

BTW, you could work around this by making the UI thread run
SCHED_FIFO, but this causes a lot of other problems, especially on a
UP system.

one partial workaround to this problem that i have used a little in
Quasimodo is to make use of the atomic_t typedef. this at least allows
inspection of queue lengths without taking the lock. you can use this
if you have a clear demarcation between queue readers and writers: the
writer takes the lock, and as the last operation before it releases
the lock, it bumps an atomic_t. the reader never tries to take the
lock unless the atomic_t is non-zero.

so, for example, the dsp thread in quasimodo doesn't take the lock on
its own request queue unless the atomic_t that indicates the length of
the queue is non-zero. this prevents the dsp thread from ever blocking
unnecessarily.

but fundamentally, if one thread wants to stick something in a data
structure that is not an atomic_t, and another thread might also be
manipulating the same location, we have to wrap it in a lock (don't
anyone dare mention lock-free synchronization or i'll strangle them :)
there is just no way around this.

so we just need to focus on designs that minimize the communication
between threads. BTW, this is another reason for my appreciation of
quasimodo's asynch parameter update model: since the dsp thread never
does anything non-atomic to the data that other threads might update,
the other threads can play with it any time they want without causing
internal code errors (it might cause non-sample-accurate or even just
plain wierd sound, though). contrast this to an event model, in which
mutexes will have to exist between the event receiver and the event
consumer threads (unless they are the same thread).

:))

--p


New Message Reply About this list Date view Thread view Subject view Author view Other groups

This archive was generated by hypermail 2b28 : pe maalis 10 2000 - 07:27:12 EST