Re: [Jackit-devel] threads and tracks
Lars Luthman <lars.luthman <at> gmail.com>
2008-01-03 00:25:15 GMT
On Thu, 2008-01-03 at 00:57 +0100, Jonatan Liljedahl wrote:
> > You could use a lock-free structure to store the data for the separate
> > tracks, e.g. a doubly linked list with atomic operations for writing the
> > "next" and "previous" node pointers. As long as the JACK thread only
> > traverses the list in the forward direction (only accesses the "next"
> > pointers) it will be safe for the UI thread to add and remove nodes in
> > the list.
> > You will also need some sort of signalling mechanism to make sure that
> > the JACK thread isn't using a particular (removed) node before you
> > actually deallocate it.
> I see, and how do I get linked lists with atomic operations? I'm currently
> using glibs lists but there is no mention of atomicy in the ref...
I don't know how the Glib list type works, but Glib has atomic pointer
reads and writes
(http://library.gnome.org/devel/glib/unstable/glib-Atomic-Operations.html) so you could easily
write your own. Inserting a new node N at the beginning of the list would just be something like
N->prev = NULL;
N->next = list_head;
list_head->prev = N;
and removing a node N would be
P = N->prev;
S = N->next;
S->prev = P;
and when iterating over the list in another thread you'd use
g_atomic_get(&n->next) instead of just reading the value of n->next
> And how might such a signalling mechanism work, do you mean like a
> conditional that the UI thread waits for after setting some "is_deleting"
> flag and before deallocating it?
Something like that. You could have a separate linked list that you
inserted "removed" nodes into and have the JACK thread set some atomic
int in them, or post some semaphor, or something else that tells the UI
thread that it's OK to delete them since the JACK thread is no longer
using nodes from an old version of the list.
> > Or, if you don't mind audio glitches when adding and removing tracks,
> > you could just use a mutex that you trylock in the JACK thread (zero all
> > output buffers when you can't lock it) and lock in the UI thread when
> > you are adding or removing tracks.
> No, I don't mind glitches in this case, so perhaps this is the easier way
> to go. But, the problem is there's 3 threads accessing the track-list:
> disk thread and jack thread traversing it (to write and read the
> ringbuffers) and the UI thread that changes the actual list
> (adding/removing tracks). if I have a tracklist_lock mutex which is held
> both by disk thread and jack thread, then they won't run in paralell, i.e.
> the trylock in the jack thread will more likely fail (when the disk thread
> is filling the ringbuffs) and i'll get glitches.
> Could I simply use two locks, one disk_tracks_lock and one
> process_tracks_lock and let the UI thread lock both?
Sounds like you need an RW lock. What you want to protect with the lock
isn't the actual ringbuffer content (the ringbuffers are supposed to be
lock-free) but the structure of the linked list so that a ringbuffer
isn't removed while you are writing to it or reading from it.
If you use a RW lock and just take a read lock in the disk and JACK
threads (using tryrdlock instead of rdlock in the JACK thread) they can
both hold the lock simultaneously. In the UI thread you would take the
write lock, which waits until all read locks are released and then won't
allow any new read locks until the write lock is released. See the man
page for pthread_rwlock_init.
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
Jackit-devel mailing list
Jackit-devel <at> lists.sourceforge.net