- PR -

外部プログラム実行時の入力待ち検出

投稿者投稿内容
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-07-28 20:51
引用:

ぐっちさんの書き込み (2007-07-28 16:49) より:
read()やreadLine()等はストリームが終了していないと読み込めなくて、
僕が作ったプログラムだと止まっているのだと思うのですが、


終了していなくても読み込めます。
止まっているのは外部プロセスが出力しないからです。

引用:

あしゅさんのおっしゃるようなスレッドを使った方法だとなぜ解決できるのでしょうか?


スレッドについて調べましたか?

read()を行っているスレッドは止まりますが、
他のスレッドは影響を受けずに処理を続けられます。
ぐっち
会議室デビュー日: 2007/07/25
投稿数: 17
投稿日時: 2007-07-30 14:48
あしゅさんありがとうございます。
スレッドについてはある程度分かっているつもりなのですが、まだまだ初心者で申し訳ないです。

まだちょっと分からないのですが、read()しているスレッドが止まっているということはreadできないということにはならないのですか?
他のスレッドは影響を受けずに処理が続けられるのは分かるのですが、読み込みができるのでしょうか?

どうぞよろしくお願い致します。
小僧
ぬし
会議室デビュー日: 2002/08/14
投稿数: 526
投稿日時: 2007-07-30 16:53
引用:

まだちょっと分からないのですが、read()しているスレッドが止まっているということはreadできないということにはならないのですか?



 読み込むデータが無い -> read出来ない -> また待つ
 読み込むデータがまた来た -> read出来る -> 処理をする

を繰り替えしてるんですよね?。ぐっちさんの言うような動作をするためには、
バッファーが常に空にならない頻度で何かを出力し続ける外部プログラムでしか
動作しないですよね。

あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-07-31 19:08
引用:

ぐっちさんの書き込み (2007-07-30 14:48) より:
まだちょっと分からないのですが、read()しているスレッドが止まっているということはreadできないということにはならないのですか?
他のスレッドは影響を受けずに処理が続けられるのは分かるのですが、読み込みができるのでしょうか?


read()は基本的に読み込めるようになるまでスレッドを停止します。
読み込みが完了するまで戻らないだけでread出来ないわけではありません。

これは外部プロセスの場合だけではなく、ファイルの場合でも同様です。
HDDから読む場合には、ヘッドのシークやディスクの回転待ちがあり、
数ミリ秒程度ではあってもスレッドの停止は確実に存在します。

この「完了するまで戻らない」ことを「ブロッキング」と呼びます。
ようするに、この時間が長いか短いかの差でしかありません。

ぐっちさんの作ったプログラムでは、Perlは標準入力に与えられたものを
そのまま標準出力に返そうとするので、Perlの外部プロセスは標準入力に
入力されない限り永遠にブロックして何も出力しようとはしません。

Java側は先に外部プロセスからの出力を読み取ろうとしているので、
入力を受け取っていないPerlの外部プロセスからは何も出力されず、
どちらも停止する状況になってしまうわけです。

Process#getOutputStream()に対してPerlへの入力行を出力してから
Process#getInputStream()を読めば、おそらく読めると思います。

#バッファリングの関係で止まる可能性もありますが未確認です。

ただし、実際のコンソール的な動きをするプログラムでは、
これらの入出力がどのような順序で起こるかは予期できないので、
マルチスレッド化して並行的に行えるようにしなくてはなりません。
ぐっち
会議室デビュー日: 2007/07/25
投稿数: 17
投稿日時: 2007-08-03 02:13
あしゅさんありがとうございます。

Process#getOutputStreamにperlプログラムへの入力を入れれば動くというのはやったのですが、これではコンソール的でないので、やめました。

read()は読み込みが完了するまでブロックするということですが、スレッドを使えばこれが回避できるのでしょうか?
その原理がイマイチ理解できないのですが、read()自体が止まってしまっては、perlプログラムが途中まで出力した内容が読み込みできない気がするのですが、そんなことはないのでしょうか?

本当に初心者ですみません。
どうぞよろしくお願いいたします。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-08-03 09:56
引用:

ぐっちさんの書き込み (2007-08-03 02:13) より:
Process#getOutputStreamにperlプログラムへの入力を入れれば動くというのはやったのですが、これではコンソール的でないので、やめました。


コンソールなんだから入力も受け付けて渡すのは当然では?
違うのならば誰が外部プロセスに入力を与えるのですか?

引用:

read()は読み込みが完了するまでブロックするということですが、スレッドを使えばこれが回避できるのでしょうか?
その原理がイマイチ理解できないのですが、read()自体が止まってしまっては、perlプログラムが途中まで出力した内容が読み込みできない気がするのですが、そんなことはないのでしょうか?


前に書いた解説を読んでいないのですか?
read()のブロッキングはどうやっても回避できません。

この辺りを理解できないのならば現状では作るのは無理でしょう。

スレッドをある程度自由に使いこなせるようになるのが先決です。
そうすれば自然に意味を理解出来るようになると思います。

Linuxなどでselect(2)を使って簡易コンソールを作るのもいいかと。
ぐっち
会議室デビュー日: 2007/07/25
投稿数: 17
投稿日時: 2007-08-07 00:13
あしゅさんありがとうございます。

入力も受け付けるのは当然なのですが、その前の出力を表示して、入出力を交互に行うのがコンソールであるので、入力を渡し、全ての出力が出るまで待ち、全ての出力を一気に表示するような感じではダメなんです。

前の書き込みはちゃんと呼んでいるのですが、僕の理解力が乏しく、ちょっと理解できておりません。

スレッドを使えば入力待ちまでの出力を読み込めるというお話だったと思うのですが、申し訳ないのですが、イマイチ理解できていません。
read()はブロッキングするのに、スレッドを上手く使えば読み込める仕組みがよく分からないんです。厚かましいようですが、そこら辺を教えていただけると幸いです。
どうぞよろしくお願い致します。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-08-07 01:17
引用:

ぐっちさんの書き込み (2007-08-07 00:13) より:
入力も受け付けるのは当然なのですが、その前の出力を表示して、入出力を交互に行うのがコンソールであるので、入力を渡し、全ての出力が出るまで待ち、全ての出力を一気に表示するような感じではダメなんです。


そうですね。それが一般的なコンソールでしょう。
とりあえず最低限の認識は一致しましたね。

引用:

スレッドを使えば入力待ちまでの出力を読み込めるというお話だったと思うのですが、申し訳ないのですが、イマイチ理解できていません。



GUIの場合の疑似コードで書いてみます。
#最初からWebで考えるとややこしいので。

□ イベント処理スレッド(ユーザー入力待機と画面制御)

このスレッドではブロックするread()は行いません。
UIイベントの処理を行う普通のプログラムです。

初期化() {
 外部プロセスを起動する
 出力待機スレッド起動(外部プロセス.getInputStream())
 出力待機スレッド起動(外部プロセス.getErrorStream())
}

GUIユーザー入力イベント(入力データ) {
 // write()もブロックする可能性があるけど簡略化
 外部プロセス.getOutputStream().write(入力データ)
}

外部プロセス出力表示イベント(出力データ) {
 // 別スレッドから非同期なタイミングで実行される
 GUIの画面に出力データを表示
}

□ 出力待機スレッド

出力待機スレッドは延々とread()し続けます。
別スレッドなのでブロックしても気にしません。
read()から復帰する毎に画面へ反映します。

ここでは簡単に「イベントを通知」と書いていますが、
実際には何らかのスレッド間通信が必要になります。
#この辺はUIの実装次第なので細かくは書きません。

public void run() {
 while (true) {
  ストリーム.read(出力データ)
  if (ストリームの終端に達した) {
   スレッドを終了する
  } else {
   // 読み込んだデータをイベント処理スレッドに
   // イベントとして通知して画面に表示させる
   外部プロセス出力表示イベントを通知(出力データ)
  }
 }
}

スキルアップ/キャリアアップ(JOB@IT)