caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* RE: threads & OCamlTK
@ 1999-03-17 15:02 Don Syme
  1999-03-17 15:57 ` William Chesters
  0 siblings, 1 reply; 11+ messages in thread
From: Don Syme @ 1999-03-17 15:02 UTC (permalink / raw)
  To: 'William Chesters', caml-list


Thanks to everyone who replied!  I'll take a good look at ThreadTk shortly.

William Chesters writes:

> > And, on a vaguely related topic, is it possible to use threads with
> > programs that also use OCamlTK? I know Tk is not threadsafe, but if
> > only one thread is calling Tk functions, then perhaps it's still OK?

>   No, `Tk.mainLoop' blocks the whole process.

Hmm... it seems not to, under Windows NT/bytecode.  Maybe this is because
Tk.mainLoop gets linked against a non-blocking library of code under
Windows.

Here's an example program where I used polling to kill looping computations.

Cheers & thanks,
Don

---------------------------------------------------------------

let loopy = ref [];;

let mk_loopy_thread id = 
  let control = ref false in
  let kill () = control := true in
  let rec loop n = 
    Format.printf "loopy thread %d computes %d@." id n;
    if !control then Thread.exit() else loop (n+1) in
  let t = Thread.create loop 0 in
  kill;;

let tk_thread = 
  Thread.create (fun () ->
    let top = openTk ()  in
  (* The widgets. They all have "top" as parent widget. *)
    let en1 = Entry.create top [TextWidth 6; Relief Sunken] in
    let lab1 = Label.create top [Text "plus"] in
    let en2 = Entry.create top [TextWidth 6 ; Relief Sunken] in
    let lab2 = Label.create top [Text "="] in
    let but1 = Button.create top [Text "loopy thread"] in
    let but2 = Button.create top [Text "kill loopy thread"] in
    let result_display = Label.create top [] in
  (* References holding values of entry widgets *)
    let n1 = ref 0
    and n2 = ref 0  in
  (* Refresh result *)
    let refresh () =
      Label.configure result_display [Text (string_of_int (!n1 + !n2))]  in
  (* Electric *)
    let get_and_refresh (w,r) =
      fun _ _ ->
	try
	  r := int_of_string (Entry.get w);
	  let _ = refresh () in
	  ()
	with
      	  Failure "int_of_string" ->
            Label.configure result_display [Text "error"]
    in
  (* Set the callbacks *)
    Entry.configure en1 [XScrollCommand (get_and_refresh (en1,n1)) ];
    Entry.configure en2 [XScrollCommand (get_and_refresh (en2,n2)) ];
    let loopy_command _ = 
      loopy := (mk_loopy_thread (List.length !loopy))::(!loopy) in
    let kill_loopy_command _ = 
      (List.hd !loopy) ();
      loopy := List.tl !loopy in
    Button.configure but1 [Command loopy_command ];
    Button.configure but2 [Command kill_loopy_command ];
  (* Map the widgets *)
    pack [en1;lab1;en2;lab2;result_display;but1;but2;] [];
  (* Make the window resizable *)
    Wm.minsize_set top 1 1;
  (* Start interaction (event-driven program) *)
    mainLoop ()) ();;

Thread.join tk_thread;; 




^ permalink raw reply	[flat|nested] 11+ messages in thread

* RE: threads & OCamlTK
  1999-03-17 15:02 threads & OCamlTK Don Syme
@ 1999-03-17 15:57 ` William Chesters
  0 siblings, 0 replies; 11+ messages in thread
From: William Chesters @ 1999-03-17 15:57 UTC (permalink / raw)
  To: Don Syme; +Cc: caml-list

Don Syme writes:
 > William Chesters writes:
 > 
 > > > And, on a vaguely related topic, is it possible to use threads with
 > > > programs that also use OCamlTK? I know Tk is not threadsafe, but if
 > > > only one thread is calling Tk functions, then perhaps it's still OK?
 > 
 > >   No, `Tk.mainLoop' blocks the whole process.
 > 
 > Hmm... it seems not to, under Windows NT/bytecode.  Maybe this is because
 > Tk.mainLoop gets linked against a non-blocking library of code under
 > Windows.

Aha, it works for me too under Linux with native code/pthreads.  I
still have the test program from months ago which supposedly
demonstrated the opposite ... and it works too!  Oh well :-).
Probably wrong link options or something.




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: threads & OCamlTK
  1999-03-23 15:07   ` Jerome Vouillon
@ 1999-03-24 17:27     ` William Chesters
  0 siblings, 0 replies; 11+ messages in thread
From: William Chesters @ 1999-03-24 17:27 UTC (permalink / raw)
  To: caml-list; +Cc: Jerome Vouillon

Jerome Vouillon writes:
 > There is a mutex that prevents two Caml threads from running
 > simultaneously.  I think what happens is that the Tk main loop
 > blocks while still holding the mutex.
 > You should try to release the mutex before entering this loop, and
 > acquire it again before each call to a Caml function. For instance,
 > in file cltkEvents.c:
 > ...

Nice idea, but it it didn't work for me, so there must be something
else wrong ...




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: threads & OCamlTK
  1999-03-22 20:04   ` William Chesters
@ 1999-03-23 16:08     ` Xavier Leroy
  0 siblings, 0 replies; 11+ messages in thread
From: Xavier Leroy @ 1999-03-23 16:08 UTC (permalink / raw)
  To: William Chesters, caml-list

> Trevor Jim writes:
>  > I've been using camltk with threads for a while.  I find it is faster
>  > to run Tk as its own process -- the thread scheduler doesn't seem to
>  > do a good job with Tk involved.
>    Yes, I have found the same (Linux w/pthreads).  CPU usage varies
> between 20% at best and near zero at worst, depending on what else is
> going on (that's why I originally thought Tk blocked threads
> completely!).

Several users reported big slowdowns in CamlTk programs using native
threads.  I have no idea on what is causing this (Tcl/Tk itself, the
native threads interface, LinuxThreads, etc), but if anyone has a
small program that reproduces the problem, I'll look at it.

- Xavier Leroy




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: threads & OCamlTK
  1999-03-22 18:39 ` Trevor Jim
  1999-03-22 20:04   ` William Chesters
@ 1999-03-23 15:07   ` Jerome Vouillon
  1999-03-24 17:27     ` William Chesters
  1 sibling, 1 reply; 11+ messages in thread
From: Jerome Vouillon @ 1999-03-23 15:07 UTC (permalink / raw)
  To: Trevor Jim, dsyme; +Cc: caml-list

On Mon, Mar 22, 1999 at 01:39:10PM -0500, Trevor Jim wrote:
> I've been using camltk with threads for a while.  I find it is faster
> to run Tk as its own process -- the thread scheduler doesn't seem to
> do a good job with Tk involved.

There is a mutex that prevents two Caml threads from running
simultaneously.  I think what happens is that the Tk main loop
blocks while still holding the mutex.
You should try to release the mutex before entering this loop, and
acquire it again before each call to a Caml function. For instance,
in file cltkEvents.c:
    +extern void enter_blocking_section (void);
    +extern void leave_blocking_section (void);

     value camltk_tk_mainloop() /* ML */
     {
       CheckInit();

       if (!signal_events) {
         /* Initialise signal handling */
         signal_events = 1;
         Tk_CreateTimerHandler(100, invoke_pending_caml_signals, NULL);
       };
    +  enter_blocking_section();
       Tk_MainLoop();
    +  leave_blocking_section();
       return Val_unit;
     }
and in file cltkCaml.c:
   +leave_blocking_section();
    callback2(*handler_code,Val_int(id),copy_string_list(argc - 2,&argv[2]));
   +enter_blocking_section();

-- Jérôme




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: threads & OCamlTK
  1999-03-22 18:39 ` Trevor Jim
@ 1999-03-22 20:04   ` William Chesters
  1999-03-23 16:08     ` Xavier Leroy
  1999-03-23 15:07   ` Jerome Vouillon
  1 sibling, 1 reply; 11+ messages in thread
From: William Chesters @ 1999-03-22 20:04 UTC (permalink / raw)
  To: caml-list

Trevor Jim writes:
 > I've been using camltk with threads for a while.  I find it is faster
 > to run Tk as its own process -- the thread scheduler doesn't seem to
 > do a good job with Tk involved.

   Yes, I have found the same (Linux w/pthreads).  CPU usage varies
between 20% at best and near zero at worst, depending on what else is
going on (that's why I originally thought Tk blocked threads
completely!).

 > My program uses one thread to run a Tk gui.  I have the gui
 > periodically poll for input from the other threads.

   I do a Fileevent.add_fileinput on a Unix pipe to which I write a
byte when I want to get control of the Tk thread.  Using a pipe to
communicate between threads is not exactly clean but it avoids
polling ...

   However I have now gone back to forking and passing code to execute
by marshalling over IPC, because of the performance problems.

   Incidentally I found the most flexible thing way to support this
model was to use Hashtbl in combination with Obj.magic, allowing for
the creations of "sessions" with arbitrarily typed persistent state.
(The interface is still type safe.)




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: threads & OCamlTK
  1999-03-15 15:05 Don Syme
  1999-03-16 17:18 ` Francois Rouaix
@ 1999-03-22 18:39 ` Trevor Jim
  1999-03-22 20:04   ` William Chesters
  1999-03-23 15:07   ` Jerome Vouillon
  1 sibling, 2 replies; 11+ messages in thread
From: Trevor Jim @ 1999-03-22 18:39 UTC (permalink / raw)
  To: dsyme; +Cc: caml-list

I've been using camltk with threads for a while.  I find it is faster
to run Tk as its own process -- the thread scheduler doesn't seem to
do a good job with Tk involved.

But, if you are running Windows this may not be possible.  The Tk
process will need to communicate with the other processes; the most
convenient way to do this is with sockets; and to the best of my
knowledge in Windows it isn't possible to use sockets unless you are
actually plugged in to the network.  So, if you want to run on your
Windows laptop, you are stuck with threads.

My program uses one thread to run a Tk gui.  I have the gui
periodically poll for input from the other threads.  I use channels
and events to do this.  Here's a useful function:

  let install_poll(poll_function) =
    let rec install () =
      Timer.add 1 (* Do this every 1 millisecond *)
        (fun () ->
          (match poll (receive guichannel) with
            None -> ()
          | Some le -> poll_function [le]);
          install()  (* After every poll we have to reinstall *)
            );
      ()
    in install()

A main thread creates guichannel and all the other threads.  The Tk
thread invokes install_poll on a polling function of its choice,
taking input from guichannel.  The other threads write to guichannel.
This assumes "open Event".

BTW this doesn't work with bytecode threads.  Windows uses native
threads but for Unix systems you may have to install ocaml with a flag
to get native threads.  Under Solaris, it works poorly even with
native threads.  So, I also use a variant of install_poll to read from
a socket instead of a channel.  It's useful when I plug my laptop in
to the network, or when I'm running Unix and I can run the Tk part in
its own process.


Anyone know a better way?

-Trevor




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: threads & OCamlTK
  1999-03-16 17:18 ` Francois Rouaix
@ 1999-03-16 17:42   ` Jun P. Furuse
  0 siblings, 0 replies; 11+ messages in thread
From: Jun P. Furuse @ 1999-03-16 17:42 UTC (permalink / raw)
  To: caml-list

Francois Rouaix wrote:

> > And, on a vaguely related topic, is it possible to use threads
> > with programs
> > that also use OCamlTK?  I know Tk is not threadsafe, but if only
> > one thread is calling Tk functions, then perhaps it's still OK?  
> 
> Yes, it should be ok. But this also includes the Tk event loop, and thus
> all callbacks. Also, there is the issue of using Thread primitives within
> a callback (e.g. having the callback on a button triggering a condition).
> In bytecode threads, this will probably not work.
> Jun and I discussed these issues a long time ago, and Jun implemented
> a modified version of the CamlTK core where the event loop would be handled
> in Caml instead of C, so as to be compatible with threads, to some extent
> (all other Tk calls still need to be in a critical section).
> I don't think we ever distributed this version, and I'm not even sure it
> would work on Windows, but you might want to check with Jun.

I implemented this threaded version of OCamlTk, called ThreadTk about
one year ago. You can see the code at the caml cvs:  

  http://camlcvs.inria.fr/cgi-bin/cvsweb.out/bazar-ocaml/camltk41/thread-tk/

Please README.threadtk for more information.

But this is based on an old release of OCamlTk and not maintained at
all for long. I may update it if I have some spare time... 

-----------------------------------------------------------------------
Jun P. Furuse 					 Jun.Furuse@inria.fr
  INRIA
    Institut National de Recherche en Informatique et en Automatique




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: threads & OCamlTK
@ 1999-03-16 17:32 William Chesters
  0 siblings, 0 replies; 11+ messages in thread
From: William Chesters @ 1999-03-16 17:32 UTC (permalink / raw)
  To: caml-list

> And, on a vaguely related topic, is it possible to use threads with
> programs that also use OCamlTK? I know Tk is not threadsafe, but if
> only one thread is calling Tk functions, then perhaps it's still OK?

   No, `Tk.mainLoop' blocks the whole process.

   To get around this, I have a little module that forks and uses
marshalling to communicate GUI code you want executed to the child
process which is running `Tk.mainLoop'.  This can be done in a
type-safe way:

	let tkDo =
	  TkServer.fork (fun topLevel ->
	    Canvas.create topLevel 0 0 400 400, ref [])
        in
	...
	tkDo (fun canvas, representation ->
	  Canvas.delete !representation;
	  representation := Canvas.create_text canvas ...)

It is not too inconvenient as long as you don't worry too much about
efficiency (I think my program ends up sending rather big marshalled
closures across the IPC).




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: threads & OCamlTK
  1999-03-15 15:05 Don Syme
@ 1999-03-16 17:18 ` Francois Rouaix
  1999-03-16 17:42   ` Jun P. Furuse
  1999-03-22 18:39 ` Trevor Jim
  1 sibling, 1 reply; 11+ messages in thread
From: Francois Rouaix @ 1999-03-16 17:18 UTC (permalink / raw)
  To: Don Syme; +Cc: caml-list

> And, on a vaguely related topic, is it possible to use threads with programs
> that also use OCamlTK?  I know Tk is not threadsafe, but if only one thread
> is calling Tk functions, then perhaps it's still OK?  

Yes, it should be ok. But this also includes the Tk event loop, and thus
all callbacks. Also, there is the issue of using Thread primitives within
a callback (e.g. having the callback on a button triggering a condition).
In bytecode threads, this will probably not work.
Jun and I discussed these issues a long time ago, and Jun implemented
a modified version of the CamlTK core where the event loop would be handled
in Caml instead of C, so as to be compatible with threads, to some extent
(all other Tk calls still need to be in a critical section).
I don't think we ever distributed this version, and I'm not even sure it
would work on Windows, but you might want to check with Jun.

--f





^ permalink raw reply	[flat|nested] 11+ messages in thread

* threads & OCamlTK
@ 1999-03-15 15:05 Don Syme
  1999-03-16 17:18 ` Francois Rouaix
  1999-03-22 18:39 ` Trevor Jim
  0 siblings, 2 replies; 11+ messages in thread
From: Don Syme @ 1999-03-15 15:05 UTC (permalink / raw)
  To: caml-list


And, on a vaguely related topic, is it possible to use threads with programs
that also use OCamlTK?  I know Tk is not threadsafe, but if only one thread
is calling Tk functions, then perhaps it's still OK?  

Also, the manual says:
  > All object files on the command line must also have been compiled with
the -thread option, 
  > which selects a special, thread-safe version of the standard library
(see chapter 8). 

But does this apply to the object files contained in libraries such as
OCamlTK, Unix, Num and Str?  

Finally, if a particular library has used non-threadsafe constructs, and you
try to link it into a threaded program, some compiler support for detecting
and warning about this might be handy.

Thanks,
Don


-----Original Message-----
From: Don Syme [mailto:dsyme@microsoft.com]
Sent: 15 March 1999 14:27
To: caml-list@inria.fr
Subject: Break under Windows NT




Hi,

Is it true that under the Windows NT version of OCaml there's no easy way of
sending the equivalent of a SIGINT to a OCaml process and have OCaml raise
an exception?  Or have I missed something?  I need to be able to
asynchronously break long running computations under NT.  BTW I'm also using
OCamlTK.

Thanks,
Don




^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~1999-03-25 13:09 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-03-17 15:02 threads & OCamlTK Don Syme
1999-03-17 15:57 ` William Chesters
  -- strict thread matches above, loose matches on Subject: below --
1999-03-16 17:32 William Chesters
1999-03-15 15:05 Don Syme
1999-03-16 17:18 ` Francois Rouaix
1999-03-16 17:42   ` Jun P. Furuse
1999-03-22 18:39 ` Trevor Jim
1999-03-22 20:04   ` William Chesters
1999-03-23 16:08     ` Xavier Leroy
1999-03-23 15:07   ` Jerome Vouillon
1999-03-24 17:27     ` William Chesters

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).