Re: Non-Blocking GUI developement



On Wed, 2007-01-24 at 09:27 -0500, Melvin Newman wrote:
> First off I am a noob with GTK+. 
> 
> Basically I am writing a program that is to interface with a server
> program over a network. As such this client program has effectively 2
> parts, 1) the backend code that connects to the server and handles all
> the data communications, 2) the front end GUI that presents the code
> to the user. 
> 
> The problem that I am running into is that I cant get the gui to
> update in a timely manner (a problem that allot of us GTK noobs seem
> to have, but one which no one answers clearly). I have tried the
> following at key places in my code: 
> 
> while(gtk_events_pending())
>         gtk_main_iteration();
> 
> And while this does update the gui, the user still has no control over
> it. For example if the user select file->exit, the menu drops down but
> the exit button has no effect. Can GTK+ run multiple signal handlers
> concurrently? 
> 
> In my first write of this program I used pthreads however I did it in
> a very very unsafe manner and the client program would frequently
> crash because both gtk_main() and my thread where doing gui
> operations. 
> 
> My main question therefore is, how do I write a responsive gui that
> can communicate in  real time over the backend networking code? Is
> pthread the way to go? If so, how do I guarantee that the pthread code
> will work on a single processor/core machine? My last pthread code ran
> ok on my dual proc desktop, but died on my single proc laptop. 

GTK+ is natively not multithreaded, signal callbacks can recurse but
not run concurrently (unless they are being run in separate threads).

To answer your questions is quite simple but requires you to know
what you are doing, you can do this in one thread - provided that
all your networking backend code always executes in small itterations
and never blocks - if this is not the case then you should use
threads, if you use threads then use GThread, not pthread directly
(gdk/gtk also need to cooperate in the threading system, so you
should use the same api).

Rule of thumb: never do this:
  while(gtk_events_pending())
          gtk_main_iteration();

Inserting that hackery into your code only means that you failed
to cooperate properly with the main loop (i.e. failed to separate
your code segments into itterations that can be easily executed
as GSources without slowing down the GUI). Typically the afore
mentioned hackery is a low-cost technique to copy/paste code
segments that were previously "while (1)" driven.

If you use threads, be sure to initialize threads early
in the initialization - this will ensure that the gdk
mechanics will create its mutex to protect/share data
structures with the programmer (thats you).

Best practice when using threads: never access objects
that belong to the main GUI thread from the worker threads,
simply use g_idle_add()/GAsyncQueue to pass data from
the worker thread to the main thread (i.e. if you need
to push progress bars or tell the GUI that you finished
an operation or any such sillyness).

If you follow that rule, there is not really any need to
call gdk_threads_enter/leave() anywhere, because you'd
only need to call it from the main thread (where you
are accessing gtk+ data), and you'd be protecting that 
data from concurrency in the same "main GUI" thread.

If you insist on using gdk_threads_enter/leave() and accessing
the gtk+ data from multiple threads, then you need to start
using your brain a little - for example, a signal callback
on a gtk+ widget implies the gdk mutex is already held (because
sombody had to aquire the mutex to access its api), but
you might have some signals fired from objects that have nothing
to do with the GUI, you might be watching the "property::notify"
of some third party GObject, in which case the lock wouldnt
be aquired when the signal is fired. Also, if you go writing
GObjects that fire a signal based on an internal timeout
GSource or something, it starts to be quite difficult
to know if the lock is down or not - like I said, its really
plain and simple thread programming, you just have to really
know what you're doing.

Cheers,
                          -Tristan





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