[ruby-list:49602] Re: IO.popen に不具合?

From: 尾川敏也 <ogw@...>
Date: 2013-09-25 13:02:03 UTC
List: ruby-list #49602
尾川です。

リプライありがとうございます。

Tanaka Akira <akr@fsij.org> wrote:
> 原因は分かりませんが、とりあえずスレッドを join してみるのはいかがでしょうか。
> もしかしたらスレッド内でなにか例外が発生していて、
> join するとそれが可視化されるかもしれません。

恥ずかしながら、スレッドについては漠然としたイメージ程度しか知らな
いのですが、何か微妙なタイミング的なものがあるかもしれないと思って、
Ruby の公式サイトのマニュアルを見ながら、見よう見まねで少しだけ試し
てはありました。

あまり意味のある結果は得られなかったので書きませんでしたが。

# -----------------------------------------------------
class String
  def |(cmdline)
    IO.popen(cmdline, "w+") do |pipe|
      t = Thread.fork {  # t に受け取っておいて
        pipe.write self
        pipe.close_write
      }
      t.join            # [A] ここで待ち合わせ
      pipe.read
                        # [B] ここはさすがに無意味ですよね?
    end
  end
end

result = "".|("myprog1 datafile.txt").|("myprog2").|("myprog3")
# -----------------------------------------------------

[A] で join したときは単純にダンマリになってしまいました。

多分、[A] で join するということは、write が終わるまで read しない
ということなので、self のサイズが pipe のバッファより大きいとバッ
ファが一杯になり、でも誰も read してスペースを空けてくれないので、
write は書き残しを抱えてそのままブロックしている、のだろうと思いま
す。

[B] は、肝心の read が終わってから、ということは write が終わって 
EOF を送ってからというタイミングなので、意味が無いだろうと思って試
していません。

[B] で join してみる意味はありますでしょうか?
あるいは他に試すとよいやり方などはありますでしょうか?

        ***

そういえば、関係があるかどうか判りませんが、こんな事もありました。

せっかちに pipe.read で一まとめに読み出そうなどとしているからマズイ
のかなと思って、pipe.read の替わりに、

      # def |() の直後に result = "" しておいて
      pipe.each do |s|
        result << s
      end
      result

で1行ずつ小分けにして読んでみたら、Ruby が不気味なエラーメッセージ
を表示しました。

     close された stream から読み出した

というような内容でした。read している最中に close する訳がないと思
うのですが、、、。


-- 
尾川敏也 ogw@shizuokanet.ne.jp
http://www6.shizuokanet.ne.jp/ogw/

In This Thread