2016-04-26 3 views
0

私は、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(); 
+0

参照:http://stackoverflow.com/help/mcve –

+0

@JoeWatkins申し訳ありませんが、実際に動作するようにサンプルコードを更新しました。 –

答えて

0

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

別のアプローチ0からwait()notify()方法を使用することですクラス

+0

'$ thread-> join()'が呼び出されたときにwait()とnotify()が必要ないという印象を受けました(2番目のスレッドが完了するまで呼び出しスレッドが確実に待機するようにします)? –

+0

@PeterVanAkelyen 'join()'は、スレッドが終了するか、別のスレッドが同時に終了するのを待つ(バリアのように使用される)ことを確認するために使用されます。私たちが目を覚ますことができるとわかるまで、waitを使ってスレッドを停止します。 – Nadir

+0

'wait()'と 'notify()'を使うようにコードを更新しましたが、私はまだ同じ結果を見ています。 –

関連する問題