[cells-gtk-devel] start-app and multithreading?

Peter Denno peter.denno at nist.gov
Tue Dec 4 16:10:58 UTC 2007


On Tuesday 04 December 2007 09:57, Peter Hildebrandt wrote:
> Peter,
>
> thanks for your reply.  I've made some progress, but before
> suggesting a patch I'd like to verify a few internals.
>
> The GTK/GDK doc says, that you're fine as long as you use gdk/gtk
> only in callback functions such as on-click-handlers.  These
> callbacks are apparently run within the lock we supply for
> gtk-main.  However in "Idles, timeouts, and input functions" [1]
> you'd need to sorround calls to gtk/gdk with the equivalent of
> with-gdk-threads.

I see that the entire main loop in gtk-app is surrounded in 
with-gdk-threads, but nothing on a finer grain. Is this the problem?

> [1]
> http://www.gnu.org/software/guile-gnome/docs/gdk/html/Threads.html

I recall reading this page after struggling with the behavior in the 
Win32 port of my program. 

It has been about a year since I've worked with cells-gtk (Not that I 
don't like it, or have given up on it.  I'm just busy with some 
server stuff and hunchentoot). 

> Now I have poked around the code for a while, and did not find any
> of those.  Does cells-gtk use "Idles, timeouts, and input
> functions"?  If yes, where?

I did a quick tutorial at
http://www.gtk.org/tutorial1.2/gtk_tut-17.html

fgrep timeout `find . -name \*.lisp` ...

widgets.lisp timeout-add. This is used in test-gtk/test-display... In 
fact I have noted that this test doesn't work in some lisps! I don't 
see in my notes where though.

Under lispworks, gtk-app does a process-wait-with-timeout. 

Grep on idle and input doesn't show anything. 

>
> My second question:  Is there somewhere a list of all windows that
> have been created using to-be?  Or will I have to hack my own using
> :after methods?  (for details why I need this, see below)

Maybe Kenny Tilton could answer that one.
>
>
> To give you an idea where things are going, here's a short write-up
> of the status quo.  Test-gtk works perfectly.  

Including the pulse behavior in test-display?

> If you have loaded 
> test-gtk and changed into the package,
>
> (start-app-in-thread 'test-gtk)
>
> starts the sample app and returns right away to the REPL.
>
> A typical example how this facility would be used is along these
> lines:
>
> ;; create a hello-world app
> (defmodel app (gtk-app)
>    ((label :accessor label :initform (c-in "") :initarg :label))
>    (:default-initargs
>
>      :title "TestApp"
>      :kids (list
>
> 	   (mk-label :text (c? (label (upper self)))))))
>
> ;; run the app
> (start-app-in-thread 'app)
>
> ;; modify a slot in the app instance and watch cells(-gtk)
> propagate the change
> (setf (label (gtk-current-app)) "Hallo Welt")
>
> Once the app is running, you can create further windows
>
> (to-be (mk-window :title "a window"))
>
> and also instances of the application
>
> (to-be (make-instance 'app))
>
> I love interactive programming :-)
>
> Three limitations apply:
>
> (1) To maintain compatibility with start-app's behavior, the window
> started by start-app-in-thread serves as the applications main
> window -- gtk-main will exit, when this one is closed.  The
> application (or the developer at the REPL) has to make sure all
> windows created by to-be are closed using not-to-be before the main
> window exits.  If he doesn't, they will remain inactive, until a
> new application is started.  (This is where a list of all open
> windows would come in handy, the solution being only a mapcar away)

This may resolve the problem I've seen where I'd have to restart lisp 
to get cells-gtk unstuck after breaking (e.g. in debugger) and 
quitting. That would be marvelous!

>
> (2) If start-app-in-thread is called while an application is still
> running, it will schedule the request and return immediately.  The
> new application is opened once the previous one is closed.  This
> limitation appears to be necessary to prevent hassle with
> applications that are not thread-safe and thus do not like being
> execute several times within the same lisp process.  If you really
> want to run your application in parallel, use (to-be (make-instance
> 'app)) or (make-be 'app).
>
> (3) For technical reasons, you CANNOT use start-app and
> start-app-in-thread from the same lisp session (i.e., if you have
> used one, you will have to RESTART your lisp session before you can
> use the other)
>
> In other words, (start-app-in-thread) behaves just like
> (start-app), the only difference being, that it returns
> immediately, running gtk in the background.
>
> Comments are welcome.  If this behavior seems to be ok, I will
> factor out the relevant changes against the current cvs version and
> provide a patch for testing.

This could be a patch that might really improve matters. Go for it!
>
>
> Here's a little write up of the technical details involved.
>
> The major issue appears to be that GTK expects gtk-main to be
> called only once for every given process.  If it is called
> repeatedly, gtk plays along nicely, if the call comes from the same
> thread as before, otherwise it does not signal an error, but simply
> discards any screen output.
>
> Interestingly, g-thread-init and gdk-thread-init may well be called
> from a different thread.  However, once gtk-main has been called,
> our process is doomed to use the same thread for subsequent calls
> to gtk-main.  I did not find this behavior documented anywhere, but
> I have come to believe that it simply reflects the C programming
> style of compile-link-run -- hence it did not occur to anyone that
> this might be a problem.
>
> As long as you run gtk-main directly from your lisp session, it is
> not a problem either, since it is always the same caller as well.
> However, once you try to spawn a thread every time you launch
> gtk-main, things inevitably break.
>
> Therefore, my code creates one thread dedicated to running
> gtk-main.  This thread is fired up the first time
> start-app-in-thread is called and should remain alive throughout
> the lisp session.  Subsequent calls to start-app-in-thread use a
> mutex to communicate start-app requests to the running thread.
>
> Regards,
> Peter
>
>
> On Mon, 03 Dec 2007 13:29:59 +0100, Peter Denno
> <peter.denno at nist.gov>
>
> wrote:
> > On Monday 03 December 2007 06:50, Peter Hildebrandt wrote:
> >> I've been trying for a while to launch a gtk application in a
> >> distinct thread (using sbcl):
> >>
> >> (sb-thread:make-thread (lambda () (cells-gtk-init) (start-app
> >> 'my-app)))
> >>
> >> The thread appears to runs fine up to the point where (gtk-main)
> >> is called, however no window is ever being displayed.
> >
> > I ran in to this problem. I don't think I resolved it. It may
> > well be the case that I still don't understand restarts
> > completely. The code to look at is probably start-app in
> > gtk-app.lisp.
> >
> > If you typically run under slime, just for experimentation, try
> > running from a command prompt instead.
> >
> >> The objective is to launch a GUI in the background, then return
> >> back to the REPL (with the GUI still runnning in the
> >> background), and modifying the underlying data structures
> >> directly, while the GUI visualizes the results.  For another app
> >> I have this up and running with cl-glut, but here I'd like to
> >> have (cells-)gtk for various reasons.
> >>
> >> Did anybody ever encounter this issue, or has any ideas how to
> >> work around it?
> >>
> >> Help is highly appreciated,
> >>
> >> Peter
> >>
> >>
> >> _______________________________________________
> >> cells-gtk-devel site list
> >> cells-gtk-devel at common-lisp.net
> >> http://common-lisp.net/mailman/listinfo/cells-gtk-devel

-- 
Best regards,
  - Peter



More information about the cells-gtk-devel mailing list