runex文が非同期で動作しない現象についてNo.08837
ohtorii さん 18/11/21 21:12
 
お疲れ様です。

runex文の引数に5(挿入)を指定すると何故か非同期で動作しないです・・・
何か分かりますか?

(マクロ)
debuginfo 1;
debuginfo "Start ping.";
runex "cmd.exe /c ping -n 10 www.google.com"
    , 0     //非同期
    , 0, ""
    , 5, "" //5(挿入)
    , 5, "" //5(挿入)
    , 1, ""
    , 2
    , 0
    , 0
    ;
debuginfo "Finish ping.";

再現させるためのデータと現象の動画(MP4)をアップしました。
https://github.com/ohtorii/test/releases/tag/20181121

*気がついたこと
引数を、5(挿入)から4(新規)へ変更すると意図したとおり非同期で動作しました。

よろしくお願いいたします。

[ ]
RE:08837 runex文が非同期で動作しない現No.08840
秀丸担当 さん 18/11/22 08:48
 

runexで5で挿入を指定する場合は、確かに標準出力などが出力されるのを待つので、
同期と同じようなことになっていました。

マクロ実行中の秀丸エディタ自身での標準出力の処理は、出力の受け取り側が自身に
なるという都合上、どうしてもこういう動作になってしまいます。
こういう場合は同期と同じになることを、ヘルプに追記させていただきます。

[ ]
RE:08840 runex文が非同期で動作しない現No.08850
ohtorii さん 18/11/26 20:28
 
お疲れ様です。

現状の秀丸エディタでは5で挿入すると同期処理になるんですね、
ヘルプに記載があるだけでも助かります、よろしくお願いします!


話が変わって、
以下は、5で挿入する場合に非同期処理を行うアイデアです、
非同期処理を行いたい場面があるため、ご一考頂けますと幸いです。

「出力の受け取り側が自身になるという都合」は、
パイプ(stdout/stderr)からの文字列読み取りと、読み取った文字列を秀丸エディタ
へ書き込む処理を
ユーザに負担して貰うことで回避できる(?)と考えています。

秀丸エディタ側で以下2つの新規関数を用意します。
・必ず非同期で実行するrunex_async関数。
 (内部実装は、Windows-APIのCreateProcessを呼び出します)
・実行ファイルの出力(stdout/stderr)をパイプから読み取り秀丸エディタへ書き込
む関数。

以下は上記関数を利用した擬似コードです、

---- 擬似コード ここから ----
//時間のかかる処理を非同期で実行する。
#handle=runex_async "foo.exe",
                    , 0, "" //標準入力
                    , 5, "" //標準出力      5(挿入)
                    , 5, "" //5標準エラー   (挿入)
                    ... 引数は以下略 ...

#exists_remaining=true;
while(#exists_remaining){
    //実行ファイルの出力(stdout/stderr)をパイプから読み取り秀丸エディタへ書
き込む
    #exists_remaining = runex_async_pipe(#handle);
 
    //
    //ユーザーはここにコードを記述する。
    //
    call my_process arg1, arg2, arg3, ...;
}

//
//ユーザーはここにコードを記述する。
//
call my_process arg1, arg2, arg3, ...;

---- 擬似コード ここまで ----


長文で申し訳ありません、よろしくお願いいたします。

[ ]
RE:08850 runex文が非同期で動作しない現No.08854
秀丸担当 さん 18/11/27 09:18
 

秀丸エディタの内部的な処理としても似たようなことをしていますが、実際はちょっ
と複雑で、別スレッドを作って読込みしながら行単位に揃えたりしています。
WSHの手法を使うと、一応そういう流れ自体は作れるようですが、結局のところ標準
出力は待機せざるを得ないようです。

  $exe="Myprogram.exe";
  #objShell=createobject("WScript.Shell");
  #objExe = member( #objShell,"Exec",$exe );
  #objStdOut = member(#objExe,"StdOut");
  while( member(#objExe,"Status") == 0 ){
    //固まる insert member(#objStdOut,"Read",100);
    sleep 30;
  }
  insert member(#objStdOut,"ReadAll");
  endmacro;

これと同じことを秀丸エディタの関数で作るとしたら結局待つことになると思います。
待たずに読み込みながらということであれば、別スレッドを作って、メインスレッド
でその様子を見るという、ちょっと複雑なことになってきます。

目的によりますが、出力自体は最後に受け取るのでよくて、その間にマクロをループ
させておきたいということであれば、上記のWSHの手法でどうでしょうか。
ただバッファの上限などがあるかもしれないです。

[ ]
RE:08854 runex文が非同期で動作しない現No.08856
ohtorii さん 18/11/27 21:24
 
お疲れ様です。

WSHの手法でReadしたときに待機することを確認しました。
ただ、今回は私の方でなんとかできそうです、
色々と情報を提供して頂きありがとうございました。
大変助かりました!


以下は蛇足です、返答は必要ありません。


> これと同じことを秀丸エディタの関数で作るとしたら結局待つことになると思いま
>す。

秀丸エディタの内部実装や過去に作成されたマクロの互換性に対して、
私は何も分からないので的外れな返答でしたら申し訳ないのですが・・・

PeekNamedPipe(Windows-API)を利用すれば即時復帰に出来ると思います。
(ご参考までに→)http://d.hatena.ne.jp/nepo_n/20051111/p1

//秀丸エディタで用意する関数の擬似コード
bool runex_async_pipe(int handle){
 if(PeekNamedPipeを呼び出しパイプにデータがあるか調べる){
  //パイプにデータ無し
  return false;
 }
 //パイプにデータあり
 パイプからデータを読み取り秀丸エディタへ挿入する処理を行う。
 return true;
}

[ ]
RE:08856 runex文が非同期で動作しない現No.08857
秀丸担当 さん 18/11/28 08:45
 

内部的な話ですが、ちょっと勘違いしていました。
標準出力だけであれば、PeekNamedPipeでしていて、別スレッドは使っていませんで
した。
ただ行単位に揃えたり標準エラー出力と混ぜたりで、PeekNamedPipeでOKでも必ずし
も取得するわけではないことになっていました。
標準入力や古い処理で別スレッドを使ったりはしていました。
とりあえずWSHの手法でなんとかなりそうということでよかったです。

[ ]