php pthread,嵌入同步作品

时间:2016-01-21 17:03:58

标签: php pthreads

这个问题遵循以下答案:Why not all threads are completed?

我试图将Joe Watkins的例子实现到几个类中:

SynchronizedWork

<?php

class SynchronizedWork extends Threaded {

    /**
     * @var int Dummy work ID
     */
    protected $id;
    /**
     * @var $resultBag Volatile Result container passed around threads
     */
    protected $resultBag;

    /**
     * @var bool Should this work be collected for garbage ?
     */
    protected $garbage = 0;

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

    public function getId()
    {
        return $this->id;
    }

    public function setResultBag(Volatile $volatile)
    {
        $this->resultBag = $volatile;
        return $this;
    }

    /**
     * @return $this Set this work ready to be collected for garbage
     */
    public function setGarbage()
    {
        $this->garbage = 1;
        return $this;
    }

    /**
     * @return bool Is this work ready to be collected for garbage ?
     */
    public function isGarbage() : bool
    {
        return $this->garbage === 1;
    }

    public function run()
    {
        $this->send(range(0, 10, $this->getId()));
    }

    public function send($result)
    {
        $this->resultBag->synchronized(function(Volatile $results, $workResult){
            $results[$this->getId()] = $workResult;
            $results->notify();
        }, $this->resultBag, $result);
    }
}

SynchronizedPool

class SynchronizedPool extends Pool {

    /**
     * @var int Pool's lifetime submitted works count
     */
    protected $submitted = 0;
    /**
     * @var int Pool's lifetime collected works count
     */
    protected $collected = 0;

    protected $resultBag;

    public function __construct($size, $clazz = Worker::class, $ctor = array())
    {
        $this->resultBag = new Volatile;
        parent::__construct($size, $clazz, $ctor);
    }

    /**
     * @param Threaded $threaded Submit the work to the pool and will be dispatched among Pool's Workers
     * @return int|void
     */
    public function submit(Threaded $threaded)
    {
        ++$this->submitted;
        $threaded->setResultBag($this->resultBag);
        parent::submit($threaded);
    }

    public function getResultBag()
    {
        return $this->resultBag;
    }

    /**
     * @return int Return the number of work submitted since the Pool has been created
     */
    public function submitted()
    {
        return $this->submitted;
    }

    /**
     * @return array Return the list of workers in the stack. Collected workers are no longer in this stack.
     */
    public function getWorks() : array
    {
        return $this->workers;
    }

    /**
     * @return int Return the number of work collected for garbage since the Pool has been created
     */
    public function collected()
    {
        return $this->collected;
    }

    public function processResult(Closure $closure)
    {
        $found = 0;
        $resultBag = $this->getResultBag();

        do {
            $workResult = $this->getResultBag()->synchronized(function() use(&$found, $resultBag) {
                while (!count($resultBag)) {
                    $resultBag->wait();
                }

                $found++;
                return $resultBag->shift();
            });

            $closure($workResult);

        } while ($found < $this->submitted());
    }
}

执行:

$pool = new SynchronizedPool(3);

$pool->submit(new SynchronizedWork(1));
$pool->submit(new SynchronizedWork(2));
$pool->submit(new SynchronizedWork(3));

$pool->processResult(function($workResult) {
    var_dump($workResult);
});

while($pool->collect()) continue;

$pool->shutdown();

似乎失败了:

    PHP Fatal error:  Uncaught RuntimeException: pthreads detected an attempt to connect to an object which has already been destroyed in /mnt/hgfs/IdeaProjects/backoffice-data/web/pthreads.php:137
Stack trace:
#0 /mnt/hgfs/IdeaProjects/backoffice-data/web/pthreads.php(137): Threaded->shift()
#1 [internal function]: SynchronizedPool->{closure}()
#2 /mnt/hgfs/IdeaProjects/backoffice-data/web/pthreads.php(138): Threaded->synchronized(Object(Closure))
#3 /mnt/hgfs/IdeaProjects/backoffice-data/web/pthreads.php(154): SynchronizedPool->processResult(Object(Closure))
#4 {main}
  thrown in /mnt/hgfs/IdeaProjects/backoffice-data/web/pthreads.php on line 137

我还尝试在提交之前调用processResult,认为ref可能在结束后被销毁(即使我没有调用collect),但在这种情况下,它只是永远等待。

为什么说resultBag已被销毁?裁判仍在池中举行不是吗?我在做什么/理解错误?

1 个答案:

答案 0 :(得分:2)

抓取pthreads的github&amp;一些问题,我找到了问题,并揭穿了下一个问题:

send方法中,我必须将线程的结果转换为实际数组,以防止它被强制转换为Volatile,它将在方法结束时被销毁(如果我理解正确的话)。这导致:

SynchronizedWork班。

public function send($result)
{
    $this->resultBag->synchronized(function(Volatile $resultBag, $workResult){
        $resultBag[$this->getId()] = (array) $workResult;
        $resultBag->notify();
    }, $this->resultBag, $result);
}

然后,将线程设置为垃圾收集,否则池收集将永远等待。

public function run()
{
    $holdenRef = range(0, 10, $this->getId());
    $this->send($holdenRef);
    $this->setGarbage();
}