io/nonblock - blocks w/threads?

A

Ara.T.Howard

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
===============================================================================
 
R

Robert Klemme

Ara.T.Howard said:
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
 
A

Ara.T.Howard

Ara.T.Howard said:
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...
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
--
===============================================================================
| 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
===============================================================================
 
R

Robert Klemme

Some answers - but not all...

Ara.T.Howard said:
Ara.T.Howard said:
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!
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.
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
 
J

Jim Weirich

Robert Klemme said:
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
}
 
A

Ara.T.Howard

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.


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
--
===============================================================================
| 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
===============================================================================
 
A

Ara.T.Howard

Robert Klemme said:

require 'thread'

Thread.exclusive{
// Critical Code Here
}

rtfm eh? ;-)

-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
===============================================================================
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

thread gurus please help... 7
Threaded IO trouble 12
sockets, windoze, and threads 4
timeout w/o timeout.rb 3
threads and blocking 0
tkscrollframe.rb 1
non-blocking io 2
Hash#values_at 2

Members online

Forum statistics

Threads
474,262
Messages
2,571,056
Members
48,769
Latest member
Clifft

Latest Threads

Top