Re: Proper way to provide gtk+ app with asynchronous data?



You can use a pipe and use 3 threads.

Use one thread for the "main" gtk loop - this will the thread the calls
gtk_main()
Use one thread to acquire data and send the data through a pipe
Use one thread to do the updates to the screen asynchrnously - it will get
its data via a pipe.

It's been a while since I've use pipes, but as I recall (dimly) it's pretty
straighforward, just do a "man 2 pipe"

Another note about using threads with gtk - do NOT do this in your
asynchronous thread:

for (;;)
{
  gdk_threads_enter()
  // wait for data (!)
  // update screen
  gdk_threads_leave();
}

do this instead

for (;;)
{
  // wait for data (don't block between gdk_threads_enter & leave)
  gdk_threads_enter()
  // update screen
  gdk_threads_leave();
}

If you do the first one, you'll lock up your application update while data
is waiting to be received.

Do not waste a lot of time trying to do gdk_threads_enter() and ...leave()
in lots of places to minimize the time spent in the gdk_threads_enter() and
...leave() areas - do NOT think of it as a critical section another words.
Keep it simple!

Another fun thing - if you try to set a breakpoint in gdb where
gdk_threads_enter() has been entered, it will lock up your entire screen
sometimes.  It pays to have two X11 sessions or 2 machines: OR better yet:
you can get around this though using Xvnc - use a virtual X11 display.  Xvnc
is part of TightVNC, do a man on vncviewer and vncserver.  There are
vncviewers available for Windows, and let me tell you, it's great.

Good luck, it's not a lot of fun to deal with threads in my opinion with
GTK.

-Rich

P.S. If you've not played with it, try fooling around with TightVNC a bit.
It's a wonderful little program and extremely useful, and the best kept
secret of Linux in my opinion.  With it, we run 5 users on a single machine,
and use dumb terminals with either Knoppix or Windoze to connect.  It
greatly reduces our IT headaches, and saved us lots of money.

----- Original Message -----
From: "Dmitry M. Shatrov" <zzidre mail ru>
To: "NavEcos" <ecos navosha com>
Cc: "zze-DEPREZ Olivier FTRD/DMI/SOP" <olivier deprez rd francetelecom com>;
<gtk-list gnome org>
Sent: Thursday, July 08, 2004 10:47 AM
Subject: Re: Proper way to provide gtk+ app with asynchronous data?


> Ok, gdk_threads_enter/leave is the way, but before coding it I'd like to
> figure out if this could be done in a message-oriented manner,
> not in cross-locking one.
>
> The proplem is that the thread that receives data does other
> time-critical things as well, so it seems improper to block it for UI
> purposes.
> What about something like messages to the main message loop?
>
> Though I can create additional helper-thread to gather data and draw it
> via gdk_therads_enter, so that receiver-thread doesn't get blocked.
> But it's an additional thread, here comes the desing cleaness issue.
>
> Regards, Dmitry.
>
> NavEcos wrote:
>
>  >Excuse me for jumping in the fray, but let me expand on this because
it's
>  >simple to use threads if you use some simple rules:
>  >
>  >In your primary thread (i.e. the thread that will eventually call
>  >gtk_main():
>  >o you MUST call g_thread_init(NULL); - call this before calling
>  >gnome_init();
>  >o when you call gtk_main() put a gdk_threads_enter() and
> gdk_threads_leave()
>  >around it, i.e.
>  >  - gdk_threads_enter()
>  >  - gdk_main()
>  >  - gdk_threads_leave()
>  >  I do not know why this must be done, just that it must be done.  I
> am not
>  >sure it even must be done, just that everybody does it!
>  >
>  >In the thread that does the asynchronous update on the display (the
>  >secondary thread)
>  >o once you get your data that will change the screen,
>  >  - call gdk_threads_enter()
>  >  - then update the screen doing whatever gtk calls you do normally
>  >  - you can OPTIONALLY (and probably want to) call gdk_flush() - if you
>  >don't, the screen won't update promptly.
>  >  - then call gdk_threads_leave()
>  >
>  >If you ever call gdk_threads_enter() twice withouth calling
>  >gdk_threads_leave() first, your screen will lockup.  That's very fun.
You
>  >need to go to another machine or log in on the console (ALT-CTL-F1) and
>  >kill -9 your program.  This *will* happen to you.
>  >
>  >If you don't call gdk_threads_enter() before updating the screen,
> you'll get
>  >a mysterous error talking about asynchronous something stuff, and your
>  >program will crash.  I don't remember the exact error, but you'll
probably
>  >do it at least once.  When you get this error, it's because you didn't
> call
>  >gdk_threads_enter() from your SECONDARY thread first.  This problem
> will be
>  >INTERMITTENT and RANDOM, so you won't be sure you have this error
> until you
>  >run the code - a lot.
>  >
>  >Never call gdk_threads_enter() from your primary thread except around
>  >gdk_main()
>  >
>  >I have a suggestion or 2 about all this BTW:
>  >
>  >1) gdk_threads_enter() should have a reference count to detect when it's
>  >called twice and notify you when it is called twice.  It might be nice
to
>  >ALLOW gdk_threads_enter() to be called multiple times by the same
> thread as
>  >long as a number of matching gdk_threads_leave() gets called.
>  >
>  >2) Also, it seems silly to me that you need to surround gdk_main() with
>  >gdk_threads_enter() and gdk_threads_leave() - calling
g_thread_init(NULL)
>  >should do that for you by setting some internal variable that will cause
>  >gdk_main() to do it automatically.  It's pretty esoteric and odd the way
>  >it's currently setup.
>  >
>  >I'm also curious why gtk_threads_init() doesn't just do the
>  >gdk_threads_enter() and gdk_threads_leave() for ALL GTK functions?  GTK
>  >knows the PID of the process that called gnome_init() - if the PID is
>  >different than the primary threads, why not just handle
> gdk_threads_enter()
>  >and .._leave() for you by all the gtk functions?  I know this is a major
>  >overhaul, but it doesn't seem like it would incurr much of a penalty in
>  >performance, especially considering how much error checking is done
> already
>  >on casting variables.
>  >
>  >-Rich
>  >
>  >
>




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