Re: start-app and multithreading?
Peter Denno <peter.denno <at> nist.gov>
2007-12-04 16:10:58 GMT
On Tuesday 04 December 2007 09:57, Peter Hildebrandt wrote:
> 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" 
> you'd need to sorround calls to gtk/gdk with the equivalent of
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?
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
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
> ;; create a hello-world app
> (defmodel app (gtk-app)
> ((label :accessor label :initform (c-in "") :initarg :label))
> :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.
> On Mon, 03 Dec 2007 13:29:59 +0100, Peter Denno
> <peter.denno <at> nist.gov>
> > 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