From: Paul Brannan Date: 2003-06-03T03:55:02+09:00 Subject: Re: Programming generators with threads On Tue, Jun 03, 2003 at 01:06:48AM +0900, Gerard A.W. Vreeswijk wrote: > Hi, in Rubytalk 55895 [ > http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/55895 ] Matz > wrote that generators can be written with Threads as well as with > Callcc. He then gave an example with Calcc. Works fine. Here is my > example with Threads. But I'm not sure whether it is good programming. > Is it free of race conditions, for example? Thanks. I tend to prefer using callcc for generators, because there are fewer messy issues with garbage collection (ideally the thread should be killed if the generator gets garbage collected). > class PrimeGenerator > > def initialize > @thread = Thread.new { # create a separate thread Probably a good idea to use Thread.current.abort_on_exception=true here, in case an exception escapes from this thread. Ideally, if an exception does escape, it should be passed from this thread to the thread that called next(). That's exactly what I did in: http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/rubycollections/rubycollections/rbc/iterator/threaded_iterator.rb?rev=1.1&content-type=text/vnd.viewcvs-markup > loop do # this thread is an infinite loop.. > > Thread.stop # going to sleep, goodnight everybody > > # Uh oh ... Brrr. Where am I? > # I have been woken up and scheduled to run. > # See (*) > > Thread.critical = true # take exclusive right to run It's a good idea to use Thread.exclusive instead of Thread.critical here, in case complex_computation raises an exception: Thread.exclusive do complex_computation end The disadvantage of using Thread.critical/exclusive is that no other threads can run. If complex_computation takes a long time to run, then this is probably not good. > # this right is necessary, because I must be kept awake > # by scheduler until next prime is computed > complex_computation # do something interesting.. > Thread.critical = false # release exclusive right > end > } > @number = 1 > end > > def next > @thread.run > return @number I think it's possible (though unlikely) for return @number to occur before complex_computation finishes. You probably want to use Thread.stop right after @thread.run, and allow the thread to wake us up to let us know the next number is ready to be returned. > end > > def complex_computation > @number += 1 > @number += 1 while Math.divisible(@number) > end > > end Paul