A
Ara.T.Howard
following is a _simulation_ of a rather complex gui i'm working on. the gui
run a procedure which, itself, is communication with many other processes via
Open3:open3 (i _need_ the stderr)... anyhow, i'm having fits getting the gui
to update and do all the io (select/read, etc). this code seems to work fine
but i am very conerned that something might bite me later... if anyone would
care to comment on the interactions between the io and threads and if this is
a reccomended approach i'd love to hear it... remember this code might look a
bit funny but it demonstrative of what my code actually does. thanks in
advance for any help/advice
==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
require 'tk'
require 'open3'
require 'io/wait'
require 'io/nonblock'
require 'thread'
$VERBOSE=nil
STDOUT.sync = STDERR.sync = true
Thread.abort_on_exception = true
threads = []
#setup gui
root = TkRoot.new
label_a=TkLabel.new root, :text=>'label_a'
label_b=TkLabel.new root, :text=>'label_b'
label_a.pack
label_b.pack
# start the gui running
threads <<
Thread.new{ Tk.mainloop }
# simulation of my processing loop - which is communcating with another
# process and updating a widget with it's output
def update label, program
command="ruby -e '#{ program }'"
i,o,e = Open3:open3 command
i.close
# we run in a thread so entire process is not blocked on io
# we DO need to wait for it to complete though, because in the real code i
# depend on values which are returned...
Thread.new do
o_done = false
e_done = false
loop do
rios, = select [o, e], nil, nil
rios.map do |rio|
break if o_done and e_done
if rio.eof?
rio == o ? o_done = true : e_done = true
next
end
# i like this better, but it hangs
# putting a critical section results in deadlock
# a semaphore is too slow...
#rio.nonblock{ text = rio.read }
# less elegant but works...
text = ''
sleep(0.42) and Thread.pass until rio.ready?
text << rio.getc while rio.ready?
label.configure :text=>text
end
end
end.join
end
# start background processing which will update the labels
threads <<
Thread.new{
update label_a, '4.times{p Time.now; sleep 1}'
}
threads <<
Thread.new{
update label_b, '4.times{|i| p "foobar_#{ i }"; sleep 1}'
}
# wait for everyone to finish
#threads.map{|t| t.join}
sleep
==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
-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
===============================================================================
run a procedure which, itself, is communication with many other processes via
Open3:open3 (i _need_ the stderr)... anyhow, i'm having fits getting the gui
to update and do all the io (select/read, etc). this code seems to work fine
but i am very conerned that something might bite me later... if anyone would
care to comment on the interactions between the io and threads and if this is
a reccomended approach i'd love to hear it... remember this code might look a
bit funny but it demonstrative of what my code actually does. thanks in
advance for any help/advice
==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
require 'tk'
require 'open3'
require 'io/wait'
require 'io/nonblock'
require 'thread'
$VERBOSE=nil
STDOUT.sync = STDERR.sync = true
Thread.abort_on_exception = true
threads = []
#setup gui
root = TkRoot.new
label_a=TkLabel.new root, :text=>'label_a'
label_b=TkLabel.new root, :text=>'label_b'
label_a.pack
label_b.pack
# start the gui running
threads <<
Thread.new{ Tk.mainloop }
# simulation of my processing loop - which is communcating with another
# process and updating a widget with it's output
def update label, program
command="ruby -e '#{ program }'"
i,o,e = Open3:open3 command
i.close
# we run in a thread so entire process is not blocked on io
# we DO need to wait for it to complete though, because in the real code i
# depend on values which are returned...
Thread.new do
o_done = false
e_done = false
loop do
rios, = select [o, e], nil, nil
rios.map do |rio|
break if o_done and e_done
if rio.eof?
rio == o ? o_done = true : e_done = true
next
end
# i like this better, but it hangs
# putting a critical section results in deadlock
# a semaphore is too slow...
#rio.nonblock{ text = rio.read }
# less elegant but works...
text = ''
sleep(0.42) and Thread.pass until rio.ready?
text << rio.getc while rio.ready?
label.configure :text=>text
end
end
end.join
end
# start background processing which will update the labels
threads <<
Thread.new{
update label_a, '4.times{p Time.now; sleep 1}'
}
threads <<
Thread.new{
update label_b, '4.times{|i| p "foobar_#{ i }"; sleep 1}'
}
# wait for everyone to finish
#threads.map{|t| t.join}
sleep
==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ==== ====
-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
===============================================================================