RE: newbie trap



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





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