unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Guile continuations
@ 2009-08-21 23:53 Linas Vepstas
  2009-08-22  3:08 ` Eric Cooper
  0 siblings, 1 reply; 4+ messages in thread
From: Linas Vepstas @ 2009-08-21 23:53 UTC (permalink / raw)
  To: Guile User

Hi,

I'm trying to find an elegant way of multi-threading between C
and scheme code, without actually using threads... Basically,
I want to do some scheme stuff for a while, break off, run some
C code for a while, then resume the scheme execution where
I left off.

I can acheive this by running in two C posix threads, and
calling scm_eval in one of the threads.

Is there a different (elegant, non-hacky) way  of doing this,
without threads?

--linas




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

* Re: Guile continuations
  2009-08-21 23:53 Guile continuations Linas Vepstas
@ 2009-08-22  3:08 ` Eric Cooper
  2009-08-22 15:26   ` Linas Vepstas
  0 siblings, 1 reply; 4+ messages in thread
From: Eric Cooper @ 2009-08-22  3:08 UTC (permalink / raw)
  To: guile-user

On Fri, Aug 21, 2009 at 06:53:29PM -0500, Linas Vepstas wrote:
> I'm trying to find an elegant way of multi-threading between C
> and scheme code, without actually using threads... Basically,
> I want to do some scheme stuff for a while, break off, run some
> C code for a while, then resume the scheme execution where
> I left off.

You can implement coroutines using call/cc, and the coroutines can be
either Scheme or C code.

Note that this only works if the threads explicitly call (yield) -- it
won't do the "right thing" when a thread does some blocking I/O
operation.  For that, you either need to define alternate versions of
those potentially blocking operations, or switch to real
(pre-emptively scheduled) POSIX threads.

Here's a simple proof of concept:

    ;;; A naive queue for thread scheduling.

    (define *queue* '())

    (define (empty-queue?)
      (null? *queue*))

    (define (enqueue x)
      (set! *queue* (append *queue* (list x))))

    (define (dequeue)
      (let ((x (car *queue*)))
	(set! *queue* (cdr *queue*))
	x))

    ;;; This starts a new thread running (proc).

    (define (fork proc)
      (call/cc
       (lambda (k)
	 (enqueue k)
	 (proc))))

    ;;; This yields the processor to another thread, if there is one.

    (define (yield)
      (call/cc
       (lambda (k)
	 (enqueue k)
	 ((dequeue)))))

    ;;; This terminates the current thread, or the entire program
    ;;; if there are no other threads left.

    (define (thread-exit)
      (if (empty-queue?)
	  (exit)
	  ((dequeue))))

    ;;; The body of a Scheme thread:

    (define (printer str)
      (lambda ()
	(let loop ((n 0))
	  (format #t "~A (~A)\n" str n)
	  (yield)
	  (loop (1+ n)))))

The C code:
    #include <libguile.h>

    SCM yield;

    SCM printer() {
	int n = 0;
	for (;;) {
	    printf("C thread (%d)\n", n);
	    scm_call_0(yield);
	    n += 1;
	}
    }

    void init_printer() {
	yield = scm_c_eval_string("yield");
	scm_c_define_gsubr("c-printer", 0, 0, 0, printer);
    }

Compile this as a shared library:
    gcc -shared -o printer.so -fPIC printer.c

Then run guile with the shared library accessible to it:

    $ LTDL_LIBRARY_PATH=. guile
    guile> (load "threads.scm")
    guile> (fork (printer "Scheme!"))
    Scheme! (0)
    guile> (load-extension "printer" "init_printer")
    guile> (fork c-printer)
    C thread (0)
    Scheme! (1)
    guile> (thread-exit)
    C thread (1)
    Scheme! (2)
    C thread (2)
    Scheme! (3)
    C thread (3)
    ....

I hope this helps (and that I haven't completely misunderstood your
question.)

-- 
Eric Cooper             e c c @ c m u . e d u




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

* Re: Guile continuations
  2009-08-22  3:08 ` Eric Cooper
@ 2009-08-22 15:26   ` Linas Vepstas
  2009-08-22 16:01     ` Eric Cooper
  0 siblings, 1 reply; 4+ messages in thread
From: Linas Vepstas @ 2009-08-22 15:26 UTC (permalink / raw)
  To: guile-user

2009/8/21 Eric Cooper <ecc@cmu.edu>:
> On Fri, Aug 21, 2009 at 06:53:29PM -0500, Linas Vepstas wrote:
>> I'm trying to find an elegant way of multi-threading between C
>> and scheme code, without actually using threads... Basically,
>> I want to do some scheme stuff for a while, break off, run some
>> C code for a while, then resume the scheme execution where
>> I left off.
>
> You can implement coroutines using call/cc, and the coroutines can be
> either Scheme or C code.

Yes, thank you!  Easy when you put it that way, and a great example
too!  I really like that simple straightforward fork/yield ... its so ...
obvious ... once you see the answer. Sheesh.

By contrast, googling "coroutine scheme" comes up with horrid
messes.  The wikipedia article on coroutines doesn't even link to
a scheme version; the Wikipedia article on continuations could
almost surely benefit from a cut-n-paste of your email.

In fact, I'm planning on cut-n-pasting that into the talk page
right now, if that's OK with you ...


--linas




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

* Re: Guile continuations
  2009-08-22 15:26   ` Linas Vepstas
@ 2009-08-22 16:01     ` Eric Cooper
  0 siblings, 0 replies; 4+ messages in thread
From: Eric Cooper @ 2009-08-22 16:01 UTC (permalink / raw)
  To: guile-user

On Sat, Aug 22, 2009 at 10:26:40AM -0500, Linas Vepstas wrote:
> The wikipedia article on coroutines doesn't even link to a scheme
> version; the Wikipedia article on continuations could almost surely
> benefit from a cut-n-paste of your email.
> 
> In fact, I'm planning on cut-n-pasting that into the talk page
> right now, if that's OK with you ...

Sure.  I think this approach was first published here:

    Haynes, C. T., Friedman, D. P., and Wand, M. 1984. Continuations
    and coroutines. In Proceedings of the 1984 ACM Symposium on LISP
    and Functional Programming (Austin, Texas, United States, August
    06 - 08, 1984). LFP '84. ACM, New York, NY, 293-298.

-- 
Eric Cooper             e c c @ c m u . e d u




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

end of thread, other threads:[~2009-08-22 16:01 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-21 23:53 Guile continuations Linas Vepstas
2009-08-22  3:08 ` Eric Cooper
2009-08-22 15:26   ` Linas Vepstas
2009-08-22 16:01     ` Eric Cooper

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 read-only IMAP folder(s) and NNTP newsgroup(s).