PHP: сбой потока при чтении потока канала

В настоящее время я разрабатываю структуру развертывания на PHP и имею некоторые проблемы с потоками и потоками.

Я хочу запустить процесс, прочитать его stdout и stderr (отдельно!), повторить его и вернуть полное содержимое потоков, когда процесс завершится.

Чтобы получить эту функциональность, я использую два потока, каждый из которых читает другой поток (stdout | stderr). Теперь проблема, с которой я столкнулся, заключается в том, что php падает, когда fgets вызывается во второй раз. (Код ошибки 0x5, смещение ошибки 0x000610e7).

После долгих проб и ошибок я понял, что когда я добавляю фиктивный массив в функцию run, сбой происходит не всегда, и он работает так, как ожидалось. Кто-нибудь знает, почему это происходит?

Я использую Windows 7, PHP 5.4.22, MSVC9, pthreads 2.0.9.

private static $pipeSpecsSilent = array(
   0 => array("pipe", "r"), // stdin
   1 => array("pipe", "w"), // stdout
   2 => array("pipe", "w")); // stderr

public function start()
{
    $this->procID = proc_open($this->executable, $this::$pipeSpecsSilent, $this->pipes);
    if (is_resource($this->procID))
    {
        $stdoutThread = new POutputThread($this->pipes[1]);
        $stderrThread = new POutputThread($this->pipes[2]);
        $stderrThread->start();
        $stdoutThread->start();

        $stdoutThread->join();
        $stderrThread->join();

        $stdout = trim($stdoutThread->getStreamValue());
        $stderr = trim($stderrThread->getStreamValue());

        $this->stop();
        return array('stdout' => $stdout, 'stderr' => $stderr);
    }
    return null;
}

/**
 * Closes all pipes and the process handle
 */
private function stop()
{
    for ($x = 0; $x < count($this->pipes); $x++)
    {
        fclose($this->pipes[$x]);
    }

    $this->resultValue = proc_close($this->procID);
}


class POutputThread extends Thread
{
    private $pipe;
    private $content;

    public function __construct($pipe)
    {
        $this->pipe = $pipe;
    }

    public function run()
    {
        $content = '';

        // this line is requires as we get a crash without it.
        // it seems like there is something odd happening?
        $stackDummy = array('', '');

        while (($line = fgets($this->pipe)))
        {
            PLog::i($line);
            $content .= $line;
        }
        $this->content = $content;
    }

    /**
     * Returns the value of the stream that was read
     *
     * @return string
     */
    public function getStreamValue()
    {
        return $this->content;
    }
}

person davidgiga1993    schedule 14.01.2015    source источник


Ответы (1)


Я нашел проблему:

Хотя я закрываю потоки после того, как все потоки завершены, кажется, что требуется закрыть поток внутри потока, который читал из него. Поэтому я заменил вызов $this->stop(); на fclose($this->pipe); внутри функции run, и все работает нормально.

person davidgiga1993    schedule 14.01.2015