On Wed, 2006-04-12 at 16:12 +0100, Ross Clement wrote:
> Thanks Tristian and Jan for the answers.
> 
> I'm not calling 
> 
>  while ( gtk_events_pending ())
>          gtk_main_iteration ();
> 
> from event handlers, they are being called from the main thread. I have
> several threads running in my program. Two are the threads created by
> PortAudio which read audio data into or out of ring buffers. The output
> ring buffer is only written to by the main thread, the input ring buffer
> is only written to by the the PortAudio thread. Audio processing is then
> done by my main thread.

I wrote a simple little program just last night that implements a simple
audio-level meter using a progress bar.  I gave up on PortAudio and
moved to RtAudio, but the principles are the same.  In my RtAudio
callback, I set a variable (this is C++, so it's a class variable) to
the peak value for the current buffer.  This callback is running in the
RtAudio thread, so I don't mess with the gui at all here.  Rather I just
have an idle event that fires in the main gui thread that just looks at
that variable and sets the progress bar.  This works very well.  In
fact, 90% of the time, this kind of timeout or idle event updating of
the gui is the best.  I don't need to do any synchronization because the
gui only reads the variable.

> 
> My gtk event handlers typically change the values of variables. The main
> thread then notices that the values have changed and performs the
> necessary actions. My program is (I believe) simple enough so that this
> mechanism for communicating GUI events to the main thread should be
> sufficient. I hope.

This sounds okay, but below you mention the gtk main loop is in the main
thread.  If that is the case, what is your event handler doing running
in a secondary thread?

> 
> Very early on I noticed that if I called gtk_main_iteration() from a
> secondary thread while the main thread was running gtk_main() that gtk
> complained. That's when I deleted gtk_main(), and made the secondary
> thread the primary one. Everything seems to be working since then, but I
> was concerned about traps for young players.

Bad.  Don't call gtk_main_iteration() from a secondary thread if the
main gtk loop is in the main thread.  I'm surprised it even works for
you.

> 
> I think I have avoided problems of reentrant code. E.g. I have a
> "record" button. If the button is pressed again during recording or
> processing of audio, the main thread will go back and start recording
> again from scratch. This seems to me, without going into great detail
> about my program, a reasonable user interface. Although while writing
> this paragraph I went over and fixed a tiny bug by making sure that the
> text of my progress bar was reset to "recording" if this happens :-)

Without seeing any of your code to get an exact picture of what you're
doing, I can't say for sure.  But what you've described doesn't feel
quite right.

I am familiar with how PortAudio (and RtAudio) works.  Here's how I'd do
it.  Leave all gui functions in the main thread.  Start the gtk main
loop and don't look back.  Nothing more will be done in the main loop.
When the user clicks the record button, check state variables and if
things are right, start up a thread that does the actual portaudio
stuff.  In the portaudio callback, don't touch the gui at all.  Just
process the buffer and use variables to communicate with the gui thread.
IE, set the peak value, the position, time elapsed, etc in simple
variables.  Then in the main thread, use an idle timeout to monitor
these variables and update the gui accordingly.  This timeout event
handling can be started in the button press callback.  If you need the
gui to communicate to the portaudio thread to start or stop it, use a
flag variable or something.  In this case, IPC is pretty simple (on-way)
and needn't use mutexes or semaphores.  

Michael


> 
> Cheers,
> 
> Ross-c
> 
> 
> On Wed, 2006-04-12 at 15:01 +0100, Andersen, Jan wrote:
> > Ross Clement wrote:
> > > Hi. I find myself writing a program that processes the gtk gui events
> > > itself. E.g. code vaguely similar to the pseudo-code:
> > > 
> > > while( large_compute_bound_job_not_finished )
> > > {
> > >   process_next_block_of_data();
> > >   gtk_progress_bar_set_fraction( progressBar, fraction );
> > >   
> > >   while ( gtk_events_pending ())
> > >           gtk_main_iteration ();
> > > }
> > > 
> > > Is this something that it is frequently sensible to do, or have I fallen
> > > into a big newbie trap?
> > >
> > I'm not sure I understand you correctly, but one thing to think about is 
> > reentrance; are the screen update functions reeantrant? I remember from my 
> > Windows days (now happily in the remote past) that anything to do with the 
> > desktop was not reentrant. What that means is that you can not update the 
> > screen from anything other than the main thread; I have got used to simply 
> > avoiding that, so I don't know if X can handle it.
> > 
> > One trap Windows programmers always used to fall in was to update a 
> > progress indicator whenever a network packet arrived; this went well as 
> > long as the update managed to return before the next packet arrived, but it 
> > caused intermittent errors and crashes when the load got too big.
> > 
> > /jan
> > _______________________________________________
> > gtk-app-devel-list mailing list
> > gtk-app-devel-list@gnome.org
> > http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
> 
> _______________________________________________
> gtk-app-devel-list mailing list
> gtk-app-devel-list@gnome.org
> http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list
> 

_______________________________________________
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

Reply via email to