Здравствуйте и заранее спасибо за проявленный интерес.
В течение последних двух недель я боролся с чем-то, что сводило меня с ума. У меня установлены APACHE (2.2.22) и PHP (5.4.3) на моем компьютере с Windows, и я пытаюсь вызвать программу из PHP-скрипта, который одновременно вызывает другую программу. Обе программы написаны на C/C++ и скомпилированы с помощью MINGW32. Что касается версии Windows, я протестировал Windows 2003 Server и Windows 7 Professional, и обе они вызывают одинаковые проблемы.
Позвольте мне представить эти две программы:
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.exe эффективно достигает обычного оператора return 0;
в своей подпрограмме main()
, так что это кажется чем-то скрытым в среде выполнения C. Кроме того, если я напишу простой mytask.exe, который просто спит в течение 10 секунд, то PHP-скрипт также блокируется на 10 секунд (или блокируется навсегда, следуя случайному поведению, о котором я только что упомянул). Другими словами, у меня нет способа заставить job.exe порождать процесс, не дожидаясь его завершения, когда я вызываю job.exe из PHP-скрипта.
Итак: есть что-то, что я делаю неправильно, когда запускаю mytask.exe, и теперь наступает вторая часть этого отступления.
Я использую функцию WINAPI CreateProcess() для порождения задач из job.exe. Что касается документации MSDN, я вызываю CreateProcess с bInheritHandles = FALSE
, чтобы дочерний процесс не приводил к взаимоблокировкам ввода-вывода с PHP-скриптом. Я также закрываю дескрипторы процессов, возвращаемые функцией CreateProcess() в структуре PROCESS_INFORMATION. Единственное, чего я не делаю, так это жду окончания процесса. С другой стороны, что касается стороны PHP, я безуспешно пробовал функции exec()
и proc_open()
PHP для вызова job.exe.
Мои последние наблюдения, однако, кажутся правильными, но они меня не убеждают, потому что я не понимаю, почему они как-то работают. Дело в том, что если mytask.exe перед сном делает fclose(stdout)
, то PHP-скрипт сразу возвращается. НО КАК??? Я сказал CreateProcess() не наследовать дескрипторы, так почему я получаю такие результаты? В любом случае, я не могу придерживаться этого патча, потому что программы, запускаемые job.exe, могут не знать о том, кто их вызывает, поэтому закрытие stdout для этих программ не является хорошим решением. В UNIX все так просто... Вы просто вызываете fork()
, закрываете стандартные потоки и затем вызываете execve
для вызова программы. В Windows я также пытался создать поток-оболочку с помощью CreateThread() (для эмуляции fork()), а затем вызвать CreateProcess() из этого потока после закрытия стандартных потоков... но это также закрыло потоки job.exe !
Весь этот вопрос можно было бы синтезировать в один: как мне выполнить из PHP программу, которая создает другие процессы?
Я надеюсь, что кто-то может пролить свет на этот вопрос... Большое спасибо!