1

こんにちは、よろしくお願いします。

過去2週間の間、私は私を狂わせている何かに苦労してきました。WindowsボックスにAPACHE(2.2.22)とPHP(5.4.3)をインストールしていて、同時に別のプログラムを呼び出すPHPスクリプトからプログラムを呼び出そうとしています。どちらのプログラムもC/C ++で記述されており、MINGW32でコンパイルされています。Windowsのバージョンに関しては、Windows2003ServerとWindows7Professionalをテストしましたが、どちらも同じ問題が発生します。

これら2つのプログラムを紹介します。

1)mytask.exe:これはバックグラウンドで実行されるプログラムであり、定期的にそのステータスをファイルに入力します。

2)job.exe:これはPHPスクリプトから呼び出したいプログラムです。その目標は、mytask.exeを(スレッドとしてではなく)独立したプロセスとして生成することです。

コンソールウィンドウから以下のコマンドを実行すると、job.exeはすぐに戻り、mytask.exeを終了するまでバックグラウンドで実行したままにします。

> job.exe spawn mytask.exe
jobid=18874111458879FED

job.exeは、mytask.exeの管理に使用される識別子をダンプすることに注意してください。例えば:

> job.exe status 18874111458879FED
RUNNING

PHPスクリプトから最初のコマンドを実行すると、PHPスクリプトがランダムに永久にブロックされることを確認しました。Windowsのタスクマネージャーを見ると、job.exeがゾンビのような状態であることがわかります。job.exereturn 0;はそのルーチンの通常のステートメントに効果的に到達していると断言できmain()ます。したがって、Cランタイムでは、それは木の下にあるもののようです。さらに、単純に10秒間スリープする単純なmytask.exeを作成すると、PHPスクリプトも10秒間ブロックされます(または、今述べたランダムな動作に従って永久にブロックされます)。つまり、PHPスクリプトからjob.exeを呼び出すと、プロセスが終了するのを待たずにjob.exeがプロセスを生成するようにする方法がありません。

つまり、mytask.exeを生成するときに間違っていることがあります。そして、ここで、この余談の2番目の部分が発生します。

WINAPI関数CreateProcess()を使用して、job.exeからタスクを生成します。MSDNのドキュメントの時点でbInheritHandles = FALSE、PHPスクリプトでI / Oデッドロックが発生する子プロセスを回避するために、を使用してCreateProcessを呼び出しています。また、PROCESS_INFORMATION構造体のCreateProcess()によって返されるプロセスハンドルを閉じます。私がしない唯一のことは、プロセスが終了するのを待つことです。一方、PHP側に関しては、 PHP関数exec()proc_open()PHP関数の両方を試しましたが、job.exeを呼び出すことができませんでした。

私の最後の観察は、しかし、正しい方法であるように見えます、それでも、なぜそれらが何とか機能するのか理解できないので、それらは私を納得させません。事実、mytask.exeがfclose(stdout)スリープする前に実行すると、PHPスクリプトはすぐに戻ります。しかし、どのように?CreateProcess()にハンドルを継承しないように指示したのに、なぜこれらの結果が得られるのですか?とにかく、job.exeによって起動されたプログラムは誰がそれらを呼び出しているかを知らない可能性があるため、このパッチに固執することはできません。したがって、これらのプログラムからstdoutを閉じることは良い解決策ではありません。UNIXでは、物事はとても単純です... 1つは単に呼び出しfork()、標準ストリームを閉じてから呼び出しますexecveプログラムを呼び出します。Windowsでは、CreateThread()を使用してラッパースレッドを作成し(fork()をエミュレートし)、標準ストリームを閉じた後にそのスレッドからCreateProcess()を呼び出すことも試みましたが、job.exeのストリームも閉じました。 !!

この質問はすべて1つの質問にまとめることができます。PHPから他のプロセスを作成するプログラムを実行するにはどうすればよいですか。

誰かがこの問題に光を当ててくれることを願っています...ありがとうございました!

4

1 に答える 1

3

私は2つの部分に分かれている解決策を釘付けにしたと思います:

1)子プロセスが終了するまで、メインプロセスが停止するという事実について。

MSDNのドキュメントの時点で、これは次の定義ですCreateProcess()

BOOL WINAPI CreateProcess(
  _In_opt_     LPCTSTR lpApplicationName,
  _Inout_opt_  LPTSTR lpCommandLine,
  _In_opt_     LPSECURITY_ATTRIBUTES lpProcessAttributes,
  _In_opt_     LPSECURITY_ATTRIBUTES lpThreadAttributes,
  _In_         BOOL bInheritHandles,
  _In_         DWORD dwCreationFlags,
  _In_opt_     LPVOID lpEnvironment,
  _In_opt_     LPCTSTR lpCurrentDirectory,
  _In_         LPSTARTUPINFO lpStartupInfo,
  _Out_        LPPROCESS_INFORMATION lpProcessInformation
);

質問で言ったように、私はに合格FALSEしましbInheritHandlesたが、私もに合格0していましたdwCreationFlags。もう少し調べDETACHED_PROCESSてみると、MSDNによるとというフラグがあります。

コンソールプロセスの場合、新しいプロセスはその親のコンソール(デフォルト)を継承しません。新しいプロセスは、後でAllocConsole関数を呼び出して、コンソールを作成できます。詳細については、コンソールの作成を参照してください。

これで、子プロセスが実行を継続しているにもかかわらず、job.exeはすぐに戻ります。

2)exec()を呼び出すと、PHPスクリプトがランダムにハングするという事実について

PHPのバグのようです。PHPセッションのコンテキストでファミリ関数を実行exec()すると、APACHEがランダムにハングする可能性があり、サーバーを再起動する必要があります。インターネットで、呼び出す前にセッションを閉じる(thru)とスクリプトがハングしないことにユーザーが気付いたスレッドを見つけました。同じことが関数にも当てはまります。したがって、私のスクリプトは次のようになります。session_write_close()exec()proc_open/proc_close

session_write_close();  //Close the session before proc_open()
$proc = proc_open($cmd,$pipedesc,$pipes);
//do stuff with pipes... 
//... and close pipes
$retval = proc_close($proc);
session_start(); //restore session

お役に立てれば。

于 2012-12-04T07:52:58.083 に答える