私は、Scanner、Parser、およびQueueクラスで作られたアプリケーションを持っています。私はPHP pthreadsを使用して、Parserクラスのrun()
メソッドでマルチスレッドを利用しようとしています。複数スレッドの複雑なオブジェクトへのアクセスPHP pthreads
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
私は、スレッドが(それは単純なオブジェクトではないとして、整数または文字列のような、)タスクキューのローカルコピーを作成しているため、この問題が発生したと仮定しますScannerクラスが使用するコピーではなく、そのコピーにタスクを追加します。私はexamples on Githubを読んだが、私は適切な解決策を考え出すことができない。
更新:wait()
とnotify()
を使用するようにコードを変更しましたが、私はまだ同じ結果が表示されています。
http://php.net/manual/en/cond.wait.phpを選ぶ維持するために、より多くのタスクがあるまで待機するスキャナを作るためにgetTask()
でCond::wait()
を使用する必要がある、とaddTask()
でCond::signal()
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();
参照:http://stackoverflow.com/help/mcve –
@JoeWatkins申し訳ありませんが、実際に動作するようにサンプルコードを更新しました。 –