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



On Sun, 2003-09-07 at 04:56, Joshua Haberman wrote:

> Does it really need to be this complicated?  

Well, it's not a simple situation.  Essentially we have two databases. 
One is being displayed by Rhythmbox (the GtkTreeView/GtkTreeModel
backing).  Another (the multithreaded RhythmDB) is being manipulated by
various threads.  Changes need to propagate both ways, so we need to
keep them in sync, but asynchronously so :)
Updating the UI every time a change is made is slow - it's best to batch
the updates.  And this way we also avoid having the update threads
having to touch the UI.

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

I have thought about it more, and I think - in essence - you are right. 
The main thread should have a polling model, because that means that if
a bunch of updates happen, the main thread can just take care of them as
fast as it can, rather than being pinged on each one.

However, I can't think of a sane way to implement this without modifying
GtkTreeView.  The part of the main thread we care about for this
discussion is the GtkTreeView, which is using a GtkTreeModel returned by
RhythmDB as a model.

How can I have the main thread poll for changes in this circumstance? 
Essentially what I want is for it to call a function to process a queued
change  (or a group of them say), before actually calling any of the
gtk_tree_model_* functions like gtk_tree_model_get_value.  I don't think
I can have the model itself emit signals like gtk_tree_model_row_changed
inside an implementation of gtk_tree_model_get.  

Given that lack - maybe what we need for now is another thread dedicated
to processing the queue of db changes and updating the UI.  Basically,
its code would look like this:

GDK_THREADS_ENTER ();

RhythmDBUpdate *data;
GTimeVal start;
g_get_current_time (&start);
g_time_val_add (&start, G_USEC_PER_SEC * 0.75);
if ((data = g_async_queue_try_pop (queue)) != NULL) {
  GTimeVal now;
  process_update (data);
  g_get_current_time (&now);
  if (compare_times (now, start) >= 0)
    break;
}

GDK_THREADS_LEAVE ();

So the basic idea is that process_update will look at a RhythmDBUpdate
structure, which would say which RhythmDBEntries have been
added/changed/deleted, and emit
gtk_tree_model_row_inserted/row_changed/row_deleted as necessary.
Note also we try to do as many updates as possible within 0.75 seconds.

One other thought occurs to me - if you were trying to implement
RhythmDB with an SQL database, I'm not sure how you could provide the
kind of fine-grained notification like "This particular entry changed"
(maybe with some sort of database-specific trigger or something?  I
don't know enough about SQL databases to say.)
Probably what they would have to do is just fall back to saying "The
database has changed".  This means that the UI would need to do a full
new query to sync up.

> 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

Right - that's basically what I'd like to do, except we have RhythmDB in
the middle.

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

I think that unfortunately with GTK+ we have no choice really.

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

Well this is a different problem really, but it would be a good idea to
do this for Rhythmbox too.  Actually it shouldn't be very hard.

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

I think it does help, thanks.  I'm curious what you think of the above.




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