[Haskell-cafe] what GUI library should i select?

Duncan Coutts duncan.coutts at worc.ox.ac.uk
Tue Nov 14 20:20:49 EST 2006

On Tue, 2006-11-14 at 10:40 +0000, Simon Peyton-Jones wrote:
> I wonder whether it'd be possible to make the gtk2hs stuff emit
> warnings if you make calls from two different threads?  Then an
> application would complain constructively rather than "becoming
> unstable".

I have three plans:

Plan 1: prevent gtk2hs initialising when using the threaded RTS.

This is what the dev version does at the moment to prevent people
shooting themselves in the foot.

Obviously this is not satisfactory as long term the threaded rts is
going to be the only option available.

The funny thing is that we can actually use Haskell threads with Gtk2Hs
perfectly well with the single threaded rts (we currently use a polling
scheme to to cooperative scheduling between gtk+ and ghc rts but there
are some non-polling possibilities that could be implemented.)

Indeed, we used to be able to have GUI stuff work fine in GHCi, but now
that GHCi uses the threaded rts we're in trouble.

Plan 2: Make the threaded rts do what we want.

This is hard and involves begging Simon M to do lots of work. The
constraints we have are that only the OS thread that initialised the GUI
can make calls to the GUI lib. So any Haskell threads doing GUI stuff
have to be running on that OS thread. Note that this really means one OS
thread, not one capability which can run on a pool of threads (with X11,
the pool might be ok as only one would be doing GUI stuff at once but on
Win32 the restrictions are even tighter). I really don't want to make
the Haskell coders have to deal with passing actions between threads to
get it right, because people will get it wrong too easily. So any thread
cunning needs to be hidden in the library so that people cn just use
threads willy nilly without there being dangerous unchecked conditions.

So one idea is to start the UI in a bound OS thread, but then we also
want to make sure that any Haskell thread that makes a GUI call only do
it in that same OS thread. Currently we cannot bind several Haskell
threads to a single OS thread. From discussions with Simon M it is clear
that making this possible is non-trivial. Then even once we have that,
to make it transparent we'd need to be able to migrate a Haskell thread
to the right OS thread if it makes a GUI call. The GUI wrapper lib would
need to arrange this and arrange for cooperative scheduling on the one
OS thread.

Lots of work.

The reason we can't just post actions to the right thread all the time
is that GUI calls are typically very short lived. Many are just reading
fields out of C struts. If every one of those needed an OS thread switch
then it'd be pretty bad. So thats why we'd need to migrate the thread
since that's a one off and after that GUI calls would be quick.

Plan 3: perhaps the IO monad isn't the right monad

It's really quite convenient to have complete access to the IO monad
when doing GUI stuff and that seems to be the design that most recent
libs have chosen.

So suppose we had a GUI monad and the boundaries between the IO and GUI
monad would take care of making sure we were using the right OS thread.

So we would initialise the GUI and then work inside the GUI monad. It'd
fork a bound thread to run the GUI lib's event loop. It'd also have to
arrange for cooperative scheduling in that OS thread. Then the GUI monad
could have a forkGUI that uses Haskell level scheduling to schedule
several GUI 'threads' in the single bound Haskell thread.

Then to do IO, we could provide an escape hatch to do IO, for blocking
stuff we could forkIO and let it run in an unbound thread. Similarly for
long running pure computations we could provide something (or just par?)
to let those run outside the GUI thread so that it doesn't block the UI.

So you'd be able to lift IO stuff into the GUI monad. As for the other
way around, I guess that could arrange for the GUI action to be added to
the GUI scheduler run queue.

Tricky bits: callbacks get run in their own unbound Haskell thread which
would therefore not run in the bound OS GUI thread. That'd be annoying
as it'd involve 2 pointless context switches per callback event. Is
there any way we could be a bit less strict. All we need is that the GUI
Haskell thread runs in the GUI OS thread, we don't mind if other Haskell
threads run in that OS thread too. So a could a callback that comes in
on that OS thread spark a Haskell thread in that same OS thread? Then we
could add the callback action to the Haskell GUI thread's runqueue and
yield to that thread.

So we might still need some RTS changes to make it work nicely. Sigh.

I'd welcome other suggestions.

If we can make it work nicely it should be great. Using light weight
threads is a nice approach to GUIs compared to the contortions that
people have to do in other languages to do everything in an event driven
style to share a single thread while avoiding ever blocking.


More information about the Haskell-Cafe mailing list