Fork/join is now implemented. Here's an example:

//////////////////
var clock = Faio::mk_alarm_clock();

concurrently$ 
  {
    println$ "One starts";
    Faio::sleep$ clock, 1.0;
    println$ "One ends";
  },
  {
    println$ "Two starts";
    Faio::sleep$ clock, 0.3;
    println$ "Two ends";
  },
  {
    println$ "Three starts";
    Faio::sleep$ clock, 0.1;
    println$ "Three ends";
  },
  {
    println$ "Four starts";
    Faio::sleep$ clock, 0.7;
    println$ "Four ends";
  }
;
////////////////////////////

This form takes an array of procedures to run in parallel.
The general form takes an iterator (stream of procedures).

The implementation is instructive and took about 15 minutes to write:

///////////////////////////
//$ Implement fork/join protocol.
open class ForkJoin 
{
  //$ Launch a set of pthreads and wait
  //$ until all of them are finished.
  proc concurrently_by_iterator  (var it:1 -> opt[1->0]) 
  {
     // Make a channel to signal termination.
     var iterm,oterm = mk_iopchannel_pair[int]();

     // Here's the actual procedure we're going to spawn. 
     noinline proc manager (var p: 1->0) () { p(); write (oterm, 1); }

     // Variable to count the number of pthreads.
     var count = 0;

   again:>
     match #it with
     | Some ?p => 
       ++count; 
       spawn_pthread$ manager p; 
      goto again; // Dreaded goto is useful!

     | None =>
       while count > 0 do
          / / Explicitly ignore return to prevent call being optimised away
          C_hack::ignore (read iterm); 
         --count;
       done
     endmatch;
  }

  proc concurrently[T with Streamable[T,1->0]] (d:T) => 
concurrently_by_iterator d.iterator;

}
////////////////////////////

The method is to create a pchannel of int. That's a nasty choice
because of issues with channels of unit. Felix is supposed to eliminate
unit values which would not be the right thing here!  ***

What we do is simple: we wrap each client procedure in a procedure
that calls the client procedure then writes down a channel.
After we have launched all the procedures, counting them, we just
read the termination notice channel that number of times.

Note carefully the noinline manager, this is to ensure a closure is
formed at the right time and captures the client procedure at
construction time.   We want to avoid "terrifying val" bugs!

Note carefully that the iterator parameter of concurrently_by_iterator
is a var. It does NOT work with a val (I know! because the
"terrifying val" bug bit me :)

Note careully the C_hack::ignore. If you don't ignore a function return value
the whole call can be elided. This is true even if the function is a generator.
[This is a CAVEAT but it is NOT a bug! Use it or lose it!]

ISSUE ***

It should work but I get this:

/Users/johnskaller/.felix/cache/text/Users/johnskaller/felix/./tfj.cpp:33:77: 
fatal error: no matching constructor
      for initialization of '::flx::rtl::unit'
      ps = (::flx::rtl::unit*)new(*PTF gcp, ::flx::rtl::unit_ptr_map, true) 
::flx::rtl::unit (0); //assign
                                                                            ^   
              ~
build/release/lib/rtl/flx_rtl.hpp:28:19: note: candidate constructor (the 
implicit copy constructor) not viable: no
      known conversion from 'int' to 'const flx::rtl::unit' for 1st argument
struct RTL_EXTERN unit {};   // unit
                  ^
Not sure why Felix is trying to init a unit value with 0.


--
john skaller
skal...@users.sourceforge.net
http://felix-lang.org




------------------------------------------------------------------------------
LogMeIn Rescue: Anywhere, Anytime Remote support for IT. Free Trial
Remotely access PCs and mobile devices and provide instant support
Improve your efficiency, and focus on delivering more value-add services
Discover what IT Professionals Know. Rescue delivers
http://p.sf.net/sfu/logmein_12329d2d
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to