Io/nonblock - blocks w/threads?


(Ara.T.Howard) #1

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|
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 think of adding an asychronous processing option to my
session library using this feature… actually i suppose it’d always be o.k.
for this to be there…

-a

···

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: http://www.ngdc.noaa.gov/stp/
TRY :: for l in ruby perl;do $l -e “print “\x3a\x2d\x29\x0a””;done
===============================================================================


(Robert) #2

“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.

    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?

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

i’m think of adding an asychronous processing option to my
session library using this feature… actually i suppose it’d always be
o.k.
for this to be there…

Regards

robert

(Ara.T.Howard) #3

“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…

    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?

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

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?

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…

-a

···

On Wed, 25 Feb 2004, Robert Klemme wrote:

===============================================================================

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: http://www.ngdc.noaa.gov/stp/
TRY :: for l in ruby perl;do $l -e “print “\x3a\x2d\x29\x0a””;done
===============================================================================


(Robert) #4

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

“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
···

On Wed, 25 Feb 2004, Robert Klemme wrote:


(Jim Weirich) #5

Robert Klemme said:

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.

require ‘thread’

Thread.exclusive{
// Critical Code Here
}

···


– Jim Weirich jim@weirichhouse.org http://onestepback.org

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)


(Ara.T.Howard) #6

Some answers - but not all…

thanks for the response…

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.

it’s the actual call to nonblock that blocks the process, try this using the
two different approaches between the print statements:

require 'tk’
require 'open3’
require 'io/nonblock’
require ‘thread’
$VERBOSE=nil
STDOUT.sync = STDERR.sync = true

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|
next if rio.eof?
p 'start…'
rio.nonblock{ text = rio.read } # blocks
#text = rio.gets # does not block
p 'finish’
l.configure :text=>text
end
end
end

Tk.mainloop

i also tried a couple of ways on inserting Thread.pass - outside of nonblock’s
block, inside of it, etc. - nothing works except protecting the call to read
by critical/exclusive which does really make sense since the point of nonblock
is not to?

-a

···

On Wed, 25 Feb 2004, Robert Klemme wrote:

===============================================================================

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: http://www.ngdc.noaa.gov/stp/
TRY :: for l in ruby perl;do $l -e “print “\x3a\x2d\x29\x0a””;done
===============================================================================


(Ara.T.Howard) #7

rtfm eh? :wink:

-a

···

On Thu, 26 Feb 2004, Jim Weirich wrote:

Robert Klemme said:

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.

require ‘thread’

Thread.exclusive{
// Critical Code Here
}

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: http://www.ngdc.noaa.gov/stp/
TRY :: for l in ruby perl;do $l -e “print “\x3a\x2d\x29\x0a””;done
===============================================================================