From: Xavier Date: 2004-03-25T20:54:32+09:00 Subject: Re: thread/fork/tk nightmares On Wed, 24 Mar 2004 20:13:46 -0700, Ara.T.Howard wrote: > > i'm working on an tk ap that drives alot of complex code, some of which is not > even ruby, and essitially gives you running progress report. i've had no end > to the woes one can get into by mixing threads and forks with tk. some > combinations even seem to hang X... in any case, the cause of the forks is > mostly open3 and i'm considering this alternative: > > def spawn command > ipath = tmpfifo > opath = tmpfifo > epath = tmpfifo > > cmd = "#{ command } < #{ ipath } 1> #{ opath } 2> #{ epath } &" > system cmd > > i = open ipath, 'w' > o = open opath, 'r' > e = open epath, 'r' > > [i,o,e] > end > > def tmpfifo > path = nil > 42.times do |i| > tpath = File.join(Dir.tmpdir, "#{ $$ }.#{ rand }.#{ i }") > system "mkfifo #{ tpath }" > next unless $? == 0 > path = tpath > at_exit{ File.unlink path rescue STDERR.puts "rm <#{ path }> failed" } > break > end > raise "could not generate tmpfifo" unless path > path > end > > obviously this is a non-portable alternative - but then again so is open3. can > anyone see any large drawbacks to this? it plays well with threads and tk > since one can: > > i,o,e = spawn 'sh' > i.puts long_running_command > > Thread.new do > while((out = o.gets)) > ... > update widgets with out > ... > end > end > > Thread.new do > while((err = e.gets)) > ... > update widgets with err > ... > end > end > > -a Nice idea IMHO. Funny, I had to write something similar yesterday to get rid of open3 warnings that were triggered when publishing my objects with drb because of its forks. This is what I did. It is much simpler as I do not need to read stdout while the spawned process runs, nor write to its stdin. I only need to get stderr and stdout separately. def runrun(rcmd) # Get a temp file tmp = Tempfile.new("runrun") # Redirect stderr into temp file po = IO.popen("#{rcmd} 2>#{tmp.path}") stdo = po.readlines po.close # Reopen temp file and read STDERR tmp.open stdr = tmp.readlines # Close and unlink temp file tmp.close! # return STDOUT and STDERR [stdo, stdr] end Regards, Xavier.