It's now possible to run pipelines of using pthreads: //////////////////////// proc psrc (cho:opchannel[int]) { for var i in 0 upto 9 do write (cho,i); done write (cho,-1); }
proc psink (chi:ipchannel[int]) { var x = read chi; while x >= 0 do print$ " "+ str x; x = read chi; done println$ "-PPP -------------"; } proc pxduce(chi: ipchannel[int], cho: opchannel[int]) { write (cho, 99); while true do var x = read chi; write (cho, x); done } spawn_pthread (psrc |-> pxduce |-> pxduce |-> psink); //////////////////////// However, the semantics of pthread/pchannels differs from fibres/schannels. The parallel pipes here work, and produce correctly ordered results. But the program doesn't terminate. Why? Because Felix pthreads are detached, and pxduce is an infinite loop which ends up starving, that is, it hangs on a channel waiting for data that never comes. Although there's no (automatic) way to join Felix detached pthreads Felix mainline driver does it. Since one of the threads is an infinite loop, Felix refuses to terminate. This fixes it: proc pxduce(chi: ipchannel[int], cho: opchannel[int]) { write (cho, 99); var x = read chi; while x >= 0 do write (cho, x); x = read chi; done write (cho, -1); } Generally Felix provides fthread/pthread and schannel/pchannel operations with syntactic and library symmetry: the same code is well formed swapping between cooperative and pre-emptive multi-tasking, with minor text edits. However the semantics is utterly distinct. Fthreads should be programmed to suicide when they lock up, which is done by treating channels with Need To Know security. That is, make sure only procedures needing to communicate on channels know their secret names. Spipes are a specifically designed kind of Witchcraft that hides the secret names of channels to ensure pipelines collapse when they have no work to do. You can use this model with pthreads and pchannels too, up to program termination where it fails, because Felix itself secretly grabs the names of the pthreads. Felix has a Need To Know: pthreads launched with spawn_pthread share a garbage collector. Because Felix uses a world-stop naive collector, it has to ensure all pthreads have suspended before sweeping can start. It can only do this if it knows all the pthreads. Note that the conservative stack-sweeping phase of the collector scans all pthread stacks: all the pthreads (except the one doing the collection) have to be frozen for this to work. In addition, experience showed that it is a bit messy for the main program to return with detached threads still operating. In particular different operating systems treat this differently. Therefore, Felix suspends program termination until all pthreads have died. This also means then where "myprogram" is your whole program (or at least the tail of it): myprogram(); and spawn_pthread myprogram; behave identically. In other words, this is a "tail spawn" like a tail call; semantics ensure that a tail call has the same behaviour as a tail spawn. Why does Felix have detached threads instead of joinable ones? =================================================== Its very important to observe that fork/join is NOT a proper abstraction. It looks like it should be the core primitive but it doesn't actually work properly. This is surprising because most people would think it is fundamental. Clearly, detached threads are weaker than fork/join because there is no way to join them. You need additional infrastructure such as pchannels to do that. Note that being "weaker" also means they're more flexible. In particular with pchannels you can easily implement fork/join. The problem with fork/join as presented in Posix is that the implementation is fundamentally unsound. When you spawn a pthread in Posix you get a handle to the thread you can wait on. You can even get some status data in some versions. The fact we have to hold some kind of specific data type as a handle immediately sets off alarm bells! The collapse of the concept is proven easily then: thread A launches thread B, collects a handle H to it, then waits on H ... DO you see it? This is not a proper model of a fork/join because one of the threads is a master and the other a slave. The only way to correctly fork/join here is for the main thread to spawn TWO threads and wait on both. Felix RTL does indeed provide joinable threads! However unless you reach under the counter you will not be able to explicitly spawn them. Instead something like: fork p1; p2; p3; join -- 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