• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:CGIでCreateProcess)

CGIでCreateProcessで起動したexeが終了してから画面出力がされるまで時間がかかる問題について

このQ&Aのポイント
  • 質問者はvc++でCGIアプリケーションを作成し、CreateProcessで某exeを起動しています。
  • exeの処理時間がかかるため、CreateProcessが成功した後でも画面出力がすぐに行われない問題が発生しています。
  • 質問者は一覧リストをiframe内に表示するためにJavaScriptでリクエストを行っていますが、リストの表示とログの追加がexeの終了後に行われます。何が原因で処理が遅れているのかわかりません。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

試してないので想像だけど、CreateProcessで起動されたプロセスが標準出力を掴んじゃってるのが原因なのではないかと。 CGIの出力って「起動されたプログラムの標準出力がWEBページとして出力される」のは判りますよね? で、CreateProcessは「親のファイルハンドルを継承する筈」なので、標準出力も親プロセスから継承して「掴みっぱなし」になってる可能性があります。 じゃないと、親プロセスと子プロセスで「同時に標準出力に文字を出力」した時に、出力がごちゃ混ぜになっちゃう。 少なくとも、各スレッドで「バッファリング」はしている筈だし「他スレッドとの競合の回避」はしている筈。 で、結果的に「親が標準出力に書き出そうとした時、子プロセスが終了して親から継承した標準出力のファイルハンドルが開放されるまで、ずっと待たされる」って状態になってるのだと思います。 この辺の処理は「unixの時代からの伝統的な手法」で「標準入力、標準出力の競合回避」が必要になると思います。

jg1wjz
質問者

お礼

chie65535 さん、ありがとうございます! 取り急ぎ、ご一報させていただきます。 原因がそうなのかは別として、理解できました。 で、CreateProcessを実行する際に、  ・ハンドルの継承をしない にしたり、プロセスの実行方法に  ・DETACHED_PROCESS を指定したりしましたが、結果は同じでした。 こういう方法ではないのですね? ##この辺の処理は「unixの時代からの伝統的な手法」で「標準入力、標準出力の競合回避」が必要になると思います。 、、、が 調べてもよくわからないのですが、 もう少し頑張って調べてみます。 また引き続きまして、アドバイスよろしくお願いします。

jg1wjz
質問者

補足

補足ですが、 CreateProcessで起動している子プロセスは、WEB系のプログラムではなく、独立して処理を行って終わるプロセスです。標準出力も特に行っていません。 (コマンドプロンプトでたたいても結果は何も表示されません <--- こんな意味で良い?) 子プロセスを終わらせると、WEBのほうは画面表示ができるので IISが子プロセスを監視している、、なんてことないですよね?

その他の回答 (2)

回答No.3

追記。 dup2(oldhandle,1);//クローズしてあったstdoutを元に戻す。 の次に close(oldhandle); して、保存してあったハンドルをクローズしないといけないかも知れません。 まあ、親プロセスが終了した段階で全ハンドルがクローズされる筈なので、閉じなくても問題は起きないと思いますが、念のため。

回答No.2

>独立して処理を行って終わるプロセスです。標準出力も特に行っていません。 それだけでは「標準出力を掴むプログラムかどうかは判らない」です。 stdoutに何も出力しないプログラムであっても、stdoutを掴んでいる可能性があります。 以下のよう「表示処理の後に子プロセスを呼ぶ」にして、挙動を確認してみて下さい。 //画面表示処理 close(1);//子プロセス起動前にstdoutをクローズして強制的に開放してしまう。 iRet = CreateProcess(0, Pbuff(ここにexe名), 0, 0, TRUE, 0, 0, 0, &startUpInfo, &PInfo ); if ( iRet != TRUE ){ CgiError("xxx", "起動できませんでした", "" ) ; return(-1); } これで、子プロセスの終了前に一覧リストが表示されるのであれば「stdoutが掴まれたままなのが原因」と判ります。 掴まれたのが原因と判明した場合は、以下のようにして下さい。 int oldhandle; oldhandle = dup(1); //後で元に戻すためstdoutをoldhandleに複写する。 close(1);//子プロセス起動前にstdoutをクローズして強制的に開放してしまう。 //この子プロセスはstdoutがクローズされた状態で実行される。 iRet = CreateProcess(0, Pbuff(ここにexe名), 0, 0, TRUE, 0, 0, 0, &startUpInfo, &PInfo ); dup2(oldhandle,1);//クローズしてあったstdoutを元に戻す。 //エラーでreturn(-1)する前に元に戻すこと。 if ( iRet != TRUE ){ CgiError("xxx", "起動できませんでした", "" ) ; return(-1); }  //この後画面表示処理 上記では、stdoutのハンドル番号を「1」と固定しています。 UNIXのC言語では、unistd.hで、stdin用に「STDIN_FILENO」、stdout用に「STDOUT_FILENO」、stderr用に「STDERR_FILENO」が定義されているので、unistd.hがインクルード可能ならunistd.hをインクルードして「1」の代りに「STDOUT_FILENO」と書いて下さい。 unix時代の伝統的手法では、本当は「ハンドル番号1をクローズ」の代りに、「/dev/nullをオープンして、そのハンドルをdup2で1番のハンドルに割り当て、と言う事をします。 「/dev/null」は「書き込んでも中身が破棄されるデバイス」で、出力を捨てる時に使います。MS-DOS系での「NULデバイス」に相当します。

jg1wjz
質問者

お礼

chie65535さん、大変詳しく有難うございます。 デッドラインがあるので、できるかどうかわかりませんが 試してみます。 お手上げだったので、大変助かりました! 今後ともよろしくお願いします。

関連するQ&A

専門家に質問してみよう