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

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

CGIでCreateProcess

vc++でCGIアプリケーションを作成しています。 今回、画面よりボタンクリックされたら、 CreateProcessで某exeを起動することになりました。 が、そのexeは処理時間がかかるため、終了を待たないで 画面出力をしたいのです。 単純に CreateProcessがうまくいったら、GetExitCodeProcesで「終わったか」を チェックしないで画面を出力しています。 が、画面出力が全部終わりません。 画面(html)はトップから出力し、iframeがあります。 表示の最後(</html>の前)にiframe内に一覧リストを表示させるよう、 JavaScriptでリクエストを行っています。 ログを見るとトップの出力までは書かれています。 その後、CreateProcessで起動したexeが終了すると、 一覧リストは表示されます。 ログも追加されています。 ##例えばexeが5分かかるとすると5分後にログが最後まで書かれています) ##画面も5分後に一覧リストが表示されます。 何故、一覧リストの処理が待たされているのかわかりません。 ソースはこんな感じです。   ↓ iRet = CreateProcess(0, Pbuff(ここにexe名), 0, 0, TRUE, 0, 0, 0, &startUpInfo, &PInfo ); if ( iRet != TRUE ){ CgiError("xxx", "起動できませんでした", "" ) ; return(-1); }  //この後画面表示処理 何か設定とか、間違ってますでしょうか? または何か他にしなければならないことがあるでしょうか? アドバイスをお願いいたします! 因みに、CreateProcessで起動するexeは最大2時間程度の処理時間になります。 よろしくお願いします。

  • jg1wjz
  • お礼率91% (148/162)

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

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8514/19356)
回答No.1

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

jg1wjz
質問者

お礼

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

jg1wjz
質問者

補足

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

その他の回答 (2)

  • chie65535
  • ベストアンサー率43% (8514/19356)
回答No.3

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

  • chie65535
  • ベストアンサー率43% (8514/19356)
回答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

  • createprocessで起動させる別.exeをモーダルで起動したい

    createprocessで起動させる別.exeをモーダルで起動したい お世話になります。 VC++6.0 MFCで開発しております。 現在A.exeのあるボタンを押すとcreateprocessでB.exeを起動させるようにしております。 B.exeを起動後、A.exeの画面表示をクリックするとA.exeがアクティブになるのです。 それを、B.exeが終了しないとA.exeがアクティブにならないように変更したいのですがどのようにすればよいでしょうか? 現状は PROCESS_INFORMATION pi; STARTUPINFO si; si.cb=sizeof(si); CreateProcess(実行EXEパス,コマンドライン,NULL,NULL,TRUE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi); で起動しております。 また、実現不可能というお答えでもいいので教えていただければと思います。 お手数ですが何卒よろしくお願いします。

  • CreateProcessでアプリケーションエラー

    先日、こちらでご質問させていただいた者です。 http://oshiete1.goo.ne.jp/kotaeru.php3?q=2211536 環境は Windows2000 Borland C++BuilderXです。 先日と同様に、 CreateProcessでmodule2.exeを起動しようとしたとき、 module2.exeが立ち上がらない現象が発生したのですが、 その際、下のような内容のエラーポップアップが表示されました。 -------------------------------------------------- module2.exe - アプリケーションエラー アプリケーションを正しく初期化できませんでした(0xc0000142)。 [OK]をクリックしてアプリケーションを終了してください。 -------------------------------------------------- 呼び出し元ではCreateProcessの戻り値を取っており、 エラーが返された場合はエラーログを出力する処理を行っているのですが 現象発生時にはエラーログが出ていなかったことから、 CreateProcessからは成功が返されたように見られます。 今回のようなアプリケーションエラー発生時に、呼び出し元でエラーを検知し エラーログを出力するようにしたいのですが、 どのようにすればよいでしょうか? ご存知の方がいらっしゃいましたら教えてください。 よろしくお願いします。

  • プロセスが終了されたかどうか調べる関数を教えてください。

    まずは下のC++のソースをご覧ください。 ------------------------------------------------ PROCESS_INFORMATION ProcessInfo; STARTUPINFO StartupInfo = { 0 }; printf ("Start of Proc\n"); CreateProcess ( NULL, "c:\proc01.exe", NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo) printf ("End of Proc\n"); ------------------------------------------------ この処理でCreateProcessで指定された"c:\proc01.exe"が起動されて 終了した時に、下のprintf()関数が実行されるのようにしたいのですが、 そのような処理をするAPI関数、またはC++関数をご存知ないでしょうか?

  • CreateProcessの制御について

    今回exeから別exe(or bat)を起動させる処理を作成しようとしているのですが、 呼び出した後(今回であればnotepad.exe)5秒程度砂時計マークがでる状態になるのです。(バッチでも同じ) なにか原因があるのでしょうか。また、対処方があれば教えてください。 【前提】 ・本体exeにウィンドウは必要なし ・バッチの場合はcmd.exeは非表示 【環境】 ・XP SP2 でコンパイル。 bcc32 5.5.1 と VB6 ・実行はXP SP2 とWin2000 双方で同様の結果 【ソース】 #include<windows.h> int WINAPI WinMain(HINSTANCE hInstance ,HINSTANCE hPrevInstance , PSTR lpCmdLine ,int nCmdShow ) { PROCESS_INFORMATION pi; STARTUPINFO si; ZeroMemory(&si,sizeof(si)); si.cb=sizeof(si); CreateProcess(NULL,"notepad.exe",NULL,NULL,FALSE,CREATE_NO_WINDOW|NORMAL_PRIORITY_CLASS, NULL,NULL,&si,&pi); CloseHandle(pi.hThread); WaitForSingleObject(pi.hProcess,INFINITE); CloseHandle(pi.hProcess); return 0; }

  • CreateProcess関数と実行後の戻り値について

    VB6からCで作られたEXEを実行した戻り値を取得したいのですが どのように記述すればよいのでしょうか? 制御が戻るまで固まらずに待ち続けるには CreateProcessを使うと良いとは思いますが、 notepadなど一方的に動作させて終了するようなサンプルしかなく、 戻り値を取得するサンプルは見当たりませんでした。 戻り値といってもCのEXEは結果を標準出力で表示されるものですが・・・ 何か良いサンプルはあるでしょうか? CreateProcessを使わない方法でも構いません。 r = CreateProcess( _ cmd, _ param, _ ByVal 0&, _ ByVal 0&, _ 0, _ NORMAL_PRIORITY_CLASS, _ ByVal 0&, _ vbNullString, _ si, _ pi _ )

  • CreateProcessのエラー

    Windows8でキーボードを任意に表示しようとしてCreateProcessでTabTip.exeを起動しようとするとエラーが出ます。 GetLastErrorでエラーコードを取得すると740が帰ってきますが、該当するコードがありません。 起動できるようにするために参考になるような情報がございましたらよろしくお願いいたします。 開発環境はVisual Stidio 2012でC++です。 ちなみにVC6ではエラーが出ずに起動できますが、任意に閉じることができません。

  • CreateProcessでEXEを起動させると残像が残る

    お世話になります。 VC++ 6.0 MFC で開発しております。 A.exeから、B.exeを起動しています。 A.exeの(画面上の)上にB.exeが表示されるのですが、 そのB.exeを動かすと白い残像みたいな跡がでます。 そのB.exeの残像みたいなのを出さないようにしたいのですがどのようにすればよいでしょうか ※B.exeを起動している間は、A.exeを操作できないようにしたいのです。 ***********実際のソースです。******** PROCESS_INFORMATION pi; STARTUPINFO si; ZeroMemory(&si,sizeof(si)); si.cb=sizeof(si);   int kekka = CreateProcess(Pass,CommandChar,NULL,NULL,TRUE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi); if(kekka==0) { CString str; str.Format("起動することはできません。); AfxMessageBox(str, MB_OK, 0); } else { WaitForSingleObject(pi.hProcess,INFINITE); } PeekMessage()とかを使えばいいとか聞いたのですが、まったくわからない状態です。 大変お手数ですが具体的に教えていただければ大変ありがたいです。 なにとぞよろしくお願いします。

  • CreateProcess関数について

    ■CreateProcess関数で実行フアイル(.exe)を呼ぶプログラムを作成しています。 ■CreateProcess関数はプロセスを作成すると直に呼出側に戻って来るが、起動したプログラムの実行結果ではない。 ■その様な事を踏まえてプログラム下記にコーテイングしました(概要) ■「呼び出し側」も「呼び出される」もCD-ROM内に有ります。 ■問題はCreateProcess関数で呼んでから、実際に画像が表示されるまでに、時間が掛かる事です。、 ■「質 問」「やりたい事」 CreateProcess関数で呼んでから、実行画面が表示される時間の間に 「その旨のなんだかのメッセージを表示したい」 例えば、Webでのダウンロードやインストールの時の様な... この様な事を、実現するのはどの様にしますか、宜しくお願いします。 STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si,sizeof(si)); si.cb=sizeof(si); ZeroMemory(&pi,sizeof(pi)); if(CreateProcess(NULL,(LPTSTR)cmdline,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)){ CloseHandle(pi.hThread); //CD-ROMから直ぐ表示出来ない場合に備えて //この間で表示に時間を要している事をメッセージ出来ないか? ShowWindow(hWnd,SW_MINIMIZE);//タスクトレイに入れる。 WaitForSingleObject(pi.hProcess,INFINITE); CloseHandle(pi.hProcess); ShowWindow(hWnd,SW_RESTORE););//タスクトレイから出す。 }

  • VB.NETでCreateProcess

    VB.NET(2003)で、別exeを起動し、終了まで待機するということをするために、 system.Diagnostics.Processクラスを使用していました。 しかし、実際に動かす環境がMetaFrameなのですが、 その環境では、このクラスは使用できないようで画面の起動すらできなくなります。 ですので、別の方法ということで、APIのCreateProcess、WaitForSingleObjectを使用するように変更したいのですが、 VB.NETでのサンプルが余り無いため、パラメータにどのように設定するかなどがよくわかりません。 API自体使ったことが無いので、根本的にわから無すぎるのです・・・ VB.NETでAPI利用サンプルが多く掲載されているサイト、 できれば、CreateProcess、WaitForSingleObjectを使用しているサンプルなどありましたら、ご教授願います。 よろしくお願いいたします。

  • CGIアプリ(一般的なこと)

    お世話になります。 頭が混乱してしまったので確認させてください。 ブラウザ上のボタンを押して、CGIアプリを実行する場合 例えばCGIアプリをabc.exeとすると abc.exeのmail処理からreturnまで処理される、 (returnの直前でブラウザに結果を出力) と、いうことで合ってますか? abc.exeの処理時間が長くても最後のreturnまで処理されますよね? cgiのタイムアウトまではいかないこととしてください。 その長い処理の間にブラウザを閉じてしまってもabc.exeは処理をし、 結果出力でエラーですよね。ブラウザは閉じられているので。 エラーについては置いときまして(^^;) mainの後とreturnの前にLOG出力させているのですが、数が合わないのです。 実際はmailの後にDB.openしているので「open」、 returnの前にDB.closeしているので「close」のようにLOGを書いています。 open-closeはペアだと思うのですが、openが多くてcloseが少ない。 これは単純にLOGに書けなかっただけでしょうか? どういう時にそのようなことが起きるのでしょうか? これは「画面が固まったのでブラウザを閉じて操作をやり直した」との申告でLOG解析をした結果です。 LOGでは固まったということは解析できなかったのですが、 確かに open、open と続いてたりしてました。 ちなみに一人だけで操作しているときです。 しばらくぶりにWebCGIの解析で、一般的な動きが...???混乱してます。 どなたか、アドバイスをお願いいたします。

    • ベストアンサー
    • CGI

専門家に質問してみよう