Re: [Rhythmbox-devel] State Of The Rhythmbox (3)

On Sat, 2003-09-06 at 23:54, Colin Walters wrote:
> So I'm back to the drawing board for a little bit.   Here's the current
> dump of my thoughts, which I've just committed to DESIGN on the rhythmdb
> branch:
> ** Multithread-capable
> We need to ensure that the UI doesn't block.  Generally this
> means using threads.

Does it really need to be this complicated?  In my experience with
threads, it pays to keep the threading model as simple as humanly
possible.  After all, the fact that you're using threads to begin with
makes things complicated enough.

Why introduce other threads?  So that each thread can block on a
different resource so no resource lays idle.  The blocking part is all
the sub-threads really *need* to do.  They can then communicate their
results to the main thread through an asynchronous queue that the main
thread can poll in its event loop.  This avoids locking entirely.

Your scenerio for attribute changes:
1. file changes on disk
2. some sub-thread notices
3. said sub-thread acquires GDK lock so that it can...
4. emit row_changed signal, which I assume causes the GUI to be updated
in this sub-thread

IMO this makes the sub-thread do more than it needs to.  Why not:
1. file changes on disk
2. some sub-thread notices
3. said sub-thread posts information about the changed file in an
asynchronous queue (no lock!) [0]
4. (later) main thread polls this queue, notices the change, and updates
the GUI from the main thread

The sub-thread does only what it has to, and therefore the application
is simpler.  In particular, I think it is good design to have only one
thread perform GUI operations (probably the main thread).

For reference, my experience comes from rewriting Audacity's audio i/o
subsystem to be multithreaded.  When recording or playing, Audacity uses
3 threads:

1. the main thread, which is the only thread that performs GUI
2. the disk thread, which blocks on disk i/o of audio data
3. the audio thread, which blocks on i/o to the soundcard

Threads 2 and 3 communicate using a lock-free ring buffer.  Thread 1
polls to discover how it should update the GUI; it polls the current
playing time to update the indicator and polls to see if the stream has
hit the end yet to know when the "play" button should pop up.

My comments are probably somewhat off-base because I am unfamiliar with
the code.  But I would be surprised if you couldn't simplify your
threading model from what you're explained here and I think it would
really benefit you to do so.


[0] Well, reading the documentation for Glib's asynchronous queue,
apparently it does use a lock.  Even so, it is easier and less intrusive
to acquire a lock for a tiny queue of pointers than to acquire a lock
over the whole UI.

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]