Some answers - but not all...

"Ara.T.Howard" <ahoward / fattire.ngdc.noaa.gov> schrieb im Newsbeitrag
news:Pine.LNX.4.44.0402250704100.30572-100000 / fattire.ngdc.noaa.gov...
> On Wed, 25 Feb 2004, Robert Klemme wrote:
>
> > "Ara.T.Howard" <Ara.T.Howard / noaa.gov> schrieb im Newsbeitrag
> > news:Pine.LNX.4.44.0402242241480.28543-100000 / fattire.ngdc.noaa.gov...
> > >
> > > this program does not work as expected w/o inserting the
> > 'Thread.critical'
> > > bits - i must say i do not understand why, can someone help me
> > understand?
> > >
> > >   require 'tk'
> > >   require 'open3'
> > >   require 'io/nonblock'
> > >   $VERBOSE=nil
> > >
> > >   r=TkRoot.new
> > >   l=TkLabel.new r, :text=>`ruby -e "p Time.now"`
> > >   l.pack
> > >
> > >   command='ruby -e "loop{p Time.now; sleep 1}"'
> > >   i,o,e = Open3::popen3 command
> > >   i.close
> > >   text = nil
> > >
> > >   Thread.new do
> > >     loop do
> > >       rios, = select [o,e], nil, nil
> > >       rios.map do |rio|
> >
> > Why do you use map here?  Apparently you don't access the result of
> > mapping so each would be more appropriate.
>
> right you are - in the actual code i do - this is a distilled example...

Ah!

> >
> > >         next if rio.eof?
> > >         Thread.critical = true             # blocks w/o this
> > >         rio.nonblock{ text = rio.read }
> > >         Thread.critical = false            # blocks w/o this
> > >         l.configure :text=>text
> > >       end
> > >     end
> > >   end
> > >
> > >   Tk.mainloop
> > >
> > >
> > > is this an o.k. technique to prevent a non-blocking read not to hand
a
> > > multi-threaded ap?
> >
>
> > I'm not really sure I understand correctly what you're after.  Could
you
> > elaborate that?
>
>   a) why is the critical section needed to prevent one thread blocking
the
>   entire process?

That's an interesting question.  One would rather expect
"Thread.critical=true" to block the whole process.  I guess, that there
are no thread context changes without these methods and assigning to
Thread.critical has the side effect of doing a context switch if possible.
I'd try to use "Thread.pass" after "l.configure..." instead of
"Thread.critical" to give other threads a chance to run and see what
happens.

>   b) is this approach (critical section) the correct way of dealing with
this
>   issue?

If the blocking is indeed caused by the loop spinning endlessly,
Thread.pass is a far better alternative.  You could as well use sleep to
achieve the same.

> more fundmenetally WHY does using 'nonblock/read' block a thread when
other io
> ops, 'gets' for example do not?  WHAT is the relationship between ioctl
ops
> and Thread.critical?

That I don't know, maybe Matz or Nobu can comment on that.

> > Generally speaking there's one piece of advice:
> >
> > When using Thread.critical= it is always best to do reset the flag in
an
> > ensure clause to make sure that the reset occurs under all conditions:
> >
> > Thread.critical = true
> > begin
> >   # do stuff
> > ensure
> >   Thread.critical = false
> > end
>
> yes of course - i've always wondered why that one doesn't take a
block...

I guess because normally it's not intended for use in the open range.
Normally one would use higher level constructs such as Mutex, Queue etc.

Regards

    robert