使用PHP pthreads访问多个线程中的复杂对象

时间:2016-04-26 23:51:28

标签: php multithreading pthreads

我有一个由Scanner,Parser和Queue类组成的应用程序。我正在尝试使用PHP pthreads在Parser类的run()方法中使用多线程。

class Scanner {
    public function performScan() {
        // Add initial task
        $initialTask = "Task 1";
        TaskQueue::addTask($initialTask);

        $i = 0;
        while(true) {
            // Get task from queue
           $task = TaskQueue::getTask();
           if ($task == null)
               break;

            // Handle task
            $parser[$i] = new Parser($task);
            $parser[$i]->start();

            // Join
            $parser[$i]->join();
            $i++;
        }

        // Done
        echo "Done\n";
    }
}

class Parser extends Thread {
    private $task;

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

    public function run() {
        // Perform a time-consuming operation
        // This operation adds an unknown number of extra tasks
        sleep(1);

        // Add new tasks to queue
        foreach(range(0, 4) as $i) {
            TaskQueue::addTask("Task {$i}");
        }
    }
}

class TaskQueue {
    private static $queue = array();

    public static function addTask($task) {
        self::$queue[] = $task;
        echo "Add task to queue!\n";
    }

    public static function getTask() {
        if (sizeof(self::$queue) > 0) {
            $task = array_shift(self::$queue);
            echo "Get task from queue!\n";
            return $task;
        }
    }
}

$scanner = new Scanner();
$scanner->performScan();

预期的情况是扫描程序一直运行,直到它没有任务(在这种情况下,无限期):

Add task to queue!
Get task from queue!
Add task to queue!
Add task to queue!
Add task to queue!
Add task to queue!
Add task to queue!
Get task from queue!
Add task to queue!
Add task to queue!
Add task to queue!
Add task to queue!
Add task to queue!
Get task from queue!
^C

相反,扫描程序在执行第一个线程后停止,因为队列中没有其他任务:

Add task to queue!
Get task from queue!
Add task to queue!
Add task to queue!
Add task to queue!
Add task to queue!
Add task to queue!
Done

我认为这是因为线程创建了TaskQueue的本地副本(因为它不是一个简单的对象,如整数或字符串),并将任务添加到该副本而不是Scanner类使用的副本。我已经阅读了examples on Github,但我无法找到合适的解决方案。

更新:我修改了代码以按照建议使用wait()notify(),但我仍然看到相同的结果。

class Scanner {
    public function performScan() {
        // Add initial task
        $initialTask = "Task 1";
        TaskQueue::addTask($initialTask);

        $i = 0;
        while(true) {
            // Get task from queue
           $task = TaskQueue::getTask();
           if ($task == null)
               break;

            // Handle task
            $parser[$i] = new Parser($task);
            $parser[$i]->start();

            // Wait
            $thread = $parser[$i];
            $thread->synchronized(function() use($thread) {
                while (!$thread->awake) {
                    $thread->wait();
                }
            });

            // Join
            $i++;
        }

        // Done
        echo "Done\n";
    }
}

class Parser extends Thread {
    private $task;

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

    public function run() {
        // Perform a time-consuming operation
        // This operation adds an unknown number of extra tasks
        sleep(1);

        // Add new tasks to queue
        foreach(range(0, 4) as $i) {
            TaskQueue::addTask("Task {$i}");
        }

        // Notify
        $this->synchronized(function(){
            $this->awake = true;
            $this->notify();
        });
    }
}

class TaskQueue {
    private static $queue = array();

    public static function addTask($task) {
        self::$queue[] = $task;
        echo "Add task to queue!\n";
    }

    public static function getTask() {
        if (sizeof(self::$queue) > 0) {
            $task = array_shift(self::$queue);
            echo "Get task from queue!\n";
            return $task;
        }
    }
}

$scanner = new Scanner();
$scanner->performScan();

1 个答案:

答案 0 :(得分:0)

您需要在Cond::wait()中使用getTask()让扫描程序等待更多任务,并在Cond::signal()插入新任务时{}} {唤醒他并继续挑选任务

http://php.net/manual/en/cond.wait.php

http://php.net/manual/en/cond.signal.php

另一种方法是使用addTask()

中的wait()notify()方法