1

端末ベースのアプリケーション用に Ocaml で新しいフロントエンドを構築しようとしています。主なアイデアは、Lwt を使用して新しいプロセスを生成することです。

let cmd = shell "./otherterminalapp" in
let p = open_process_full cmd;

その後、プロセスの標準入力に何かを書き込んで、外部アプリでコマンドを実行します。

 Lwt_io.write_line p#stdin "some command" >>= (fun _ -> Lwt_io.flush p#stdin)

コマンドからの結果を読み取ると、Lwt_io.read_line_opt. 行がなくなるまで読むにはどうすればよいですか?私が直面している問題は、プログラムが特定の時点でハングすることです。で読むとread_line_opt、最後に到達したときに、プロセスが新しい出力をリダイレクトするのを待っているようです。

どうすればこれにアプローチできますか?

私がやろうとしていることの具体例: (端末ベースのアプリケーションは ocamldebug です)

プログラムのソース コード:

open Lwt
open Lwt_unix
open Lwt_process
let () =
  let run () =
    let cmd = shell "ocamldebug test.d.byte" in
    let dbgr = open_process_full cmd in
    (((((((Lwt_io.write_line dbgr#stdin "info modules") >>=
            (fun _  -> Lwt_io.flush dbgr#stdin))
           >>= (fun _  -> Lwt_io.read_line_opt dbgr#stdout))
          >>=
          (fun s  ->
             (match s with
              | Some l -> print_endline l
              | None  -> print_endline "nothing here! ");
             Lwt_io.read_line_opt dbgr#stdout))
         >>=
         (fun s  ->
            (match s with
             | Some l -> print_endline l
             | None  -> print_endline "nothing here! ");
            Lwt_io.read_line_opt dbgr#stdout))
        >>=
        (fun s  ->
           (match s with
            | Some l -> print_endline l
            | None  -> print_endline "nothing here! ");
           Lwt_io.read_line_opt dbgr#stdout))
       >>=
       (fun s  ->
          (match s with
           | Some l -> print_endline l
           | None  -> print_endline "nothing here! ");
          Lwt_io.read_line_opt dbgr#stdout))
      >>=
      (fun s  ->
         (match s with
          | Some l -> print_endline l
          | None  -> print_endline "nothing here! ");
         Lwt.return ()) in
  Lwt_main.run (run ())

通常は で実行するocamldebugtest.d.byte、端末に次のように表示されます。

    OCaml Debugger version 4.03.0

(ocd) info modules
Loading program... done.
Used modules: 
Std_exit Test Pervasives CamlinternalFormatBasics
(ocd) 

上記のプログラムを実行すると、次のように表示されます。

    OCaml Debugger version 4.03.0

(ocd) Loading program... Used modules: 
Std_exit Test Pervasives CamlinternalFormatBasics

そして、ここでハングアップします...、私のプログラムは終了しません。端末で Ctrl-c/Ctrl-c を実行しても、アクティブな ocamlrun プロセスがあります。ただし、端末は応答します。

ここで明らかな何かが欠けていますか?

4

1 に答える 1

3

への呼び出しは遅延値を返します。これは、チャネルが改行で終了する文字列を読み取ったとき、またはチャネルが閉じられた場合にLwt.read_line_opt後で決定されます。ファイルの終わりの状態があった場合、チャネルは閉じられます。通常のファイルの場合、ファイル ポインタがファイルの最後に到達すると、ファイルの終わりの状態が発生します。サブプロセスとの通信に使用されるパイプの場合、反対側がパイプに関連付けられたファイル記述子を閉じると、ファイル終了条件が発生します。Some dataNone

プログラムはocamldebug入力または出力を閉じません。Ctrl-Dこれは対話型プログラムであり、無限の時間、またはユーザーがコマンドを押すか使用してプログラムを閉じるまで、ユーザーと対話する準備ができていますquit

あなたのシナリオでは、info modulesコマンドをチャネルの入力に書き込みました。プロセスは 3 行で応答しました (各行は改行で終わるデータです)。その後、サブプロセスは次の入力を待ち始めました。(ocd)改行文字で終了していないため、プロンプトは表示されません。プログラムはハングアップしませんでした。サブプロセスからの出力をまだ待っており、サブプロセスはユーザーからの入力を待っています (デッドロック)。

異なるコマンドからの出力を本当に区別する必要がある場合は、サブプロセスの出力でプロンプトを追跡する必要があります。read_line*プロンプトは改行で終了しないため、一連の関数は行バッファリングされているため、これらの関数に依存することはできません。利用可能なすべての文字を読み、手動でプロンプトを見つける必要があります。

一方、異なるコマンドの出力を実際に区別する必要がない場合は、プロンプトを無視できます (実際には、より良い出力を得るために、プロンプトを除外することもできます)。その場合、2 つの並行サブルーチンが存在します。1 つは入力の供給を担当し、もう 1 つはすべての出力を読み取ってダンプしますが、データの内容は実際には持ち越されません。

于 2016-12-12T13:14:59.637 に答える