threads and tracks

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

threads and tracks

Jonatan Liljedahl
Hi,
jack ringbuffers are lock-free, but in my app I have multiple tracks
which each contains a jack port and a ringbuffer. A disk thread is
reading sound from disk into these ringbuffers and the jack process()
thread is writing it out to jack.
So, since the list of tracks is dynamic, I still need to do some locking
when the UI thread changes it (adds or removes a track), right? but if I
have a lock for the track-list, and lock it both in process() and
disk_thread(), then they won't run in parallel (disk_thread feeding the
ringbuffers and process() reading them)...
any tips?

--
/Jonatan         [ http://kymatica.com ]

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel
Reply | Threaded
Open this post in threaded view
|

Re: threads and tracks

lars.luthman (Bugzilla)
On Wed, 2008-01-02 at 17:51 +0100, Jonatan Liljedahl wrote:

> jack ringbuffers are lock-free, but in my app I have multiple tracks
> which each contains a jack port and a ringbuffer. A disk thread is
> reading sound from disk into these ringbuffers and the jack process()
> thread is writing it out to jack.
> So, since the list of tracks is dynamic, I still need to do some locking
> when the UI thread changes it (adds or removes a track), right? but if I
> have a lock for the track-list, and lock it both in process() and
> disk_thread(), then they won't run in parallel (disk_thread feeding the
> ringbuffers and process() reading them)...
> any tips?
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.

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.


--ll

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel

signature.asc (196 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: threads and tracks

Jonatan Liljedahl
> On Wed, 2008-01-02 at 17:51 +0100, Jonatan Liljedahl wrote:
>> jack ringbuffers are lock-free, but in my app I have multiple tracks
>> which each contains a jack port and a ringbuffer. A disk thread is
>> reading sound from disk into these ringbuffers and the jack process()
>> thread is writing it out to jack.
>> So, since the list of tracks is dynamic, I still need to do some locking
>> when the UI thread changes it (adds or removes a track), right? but if I
>> have a lock for the track-list, and lock it both in process() and
>> disk_thread(), then they won't run in parallel (disk_thread feeding the
>> ringbuffers and process() reading them)...
>> any tips?
>
> 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...
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?

> 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? Perhaps I should
mention that the disk thread already has a mutex and a condition to wake
it up from the jack thread when there's place in the ringbuffs for more
data...

I'm a total novice regarding threads, so thanks a lot for your help. :)

/Jonatan


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel
Reply | Threaded
Open this post in threaded view
|

Re: threads and tracks

lars.luthman (Bugzilla)
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;
 if (list_head)
   list_head->prev = N;
 g_atomic_set(&list_head, N);

and removing a node N would be

 P = N->prev;
 S = N->next;
 if (S)
   S->prev = P;
 if (P)
   g_atomic_set(&P->next, S);
 else
   g_atomic_set(&list_head, S);

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
directly.


> 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.


--ll

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel

signature.asc (196 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: threads and tracks

Jonatan Liljedahl
Lars Luthman wrote:
> On Thu, 2008-01-03 at 00:57 +0100, Jonatan Liljedahl wrote:
...

>>> 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 was exactly what I needed, and it works just fine!
Big thanks!

--
/Jonatan         [ http://kymatica.com ]

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Jackit-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/jackit-devel