Разделяемая блочная память PHP и форк

Я пытаюсь создать счетчик, который использует общую блочную память, просто посмотрите код:

    $i=0; $counter = new counter('g');
while($i<3){
  $pid = pcntl_fork();
  echo $counter->get()."\t".$i."\t".$pid."\n";
  $i++;
}

class counter {
  protected static $projID = array();
  protected $t_key;
  protected $length;

  function __construct($projID){
    !in_array( $projID, self::$projID) or die('Using duplicate project identifer "'.$projID.'" for creating counter');
    self::$projID[] = $projID;
    $this->t_key = ftok(__FILE__, $projID);
    $this->shmid = shmop_open($t_key, 'c', 0755, 64);
    $this->length = shmop_write($this->shmid, 0, 0);
    shmop_close($this->shmid);
  }

  function get(){
    $sem = sem_get($this->t_key, 1);
    sem_acquire($sem);
      $shmid = shmop_open($this->t_key, 'c', 0755, 64);
      $inc = shmop_read($shmid, 0, $this->length);
      $this->length = shmop_write($shmid, $inc+1, 0);
      shmop_close($shmid);
    sem_release($sem);
    return $inc;
  }
}

Но я получаю странный результат

7   0   2567
8   1   2568
9   0   0
1   1   0
2   2   2569
40  1   2570
4   2   2572
3   2   0
51  2   2571
52  1   0
63  2   0
5   2   0
64  2   2573
65  2   0

Я хочу создать этот класс для чтения и записи строк в файле в многопоточности.


person Kein    schedule 06.04.2011    source источник


Ответы (2)


Вы вообще не завершаете дочерние процессы, они никогда не закончатся. Вы также не проверяете, правильно ли разветвился процесс или нет, нет контроля над тем, что закончилось обработкой и в каком порядке. Разветвление процесса на самом деле не является многопоточностью, которую обеспечивают другие языки, все, что происходит, это то, что текущий процесс копируется, а переменные совместно используются - ваш $i не закончится на 3, и нет гарантии, какой процесс завершится первым или прошлой.

Попробуйте с:

while($i < 3)
{
    $pid = pcntl_fork();

    if($pid == -1)
    {
        // some sort of message that the process wasn't forked 
        exit(1);
    }
    else
    {
        if($pid)
        {
            pcntl_wait($status); // refer to PHP manual to check what this function does
        }
        else
        {
            // enter your code here, for whatever you want to be done in parallel
            // bear in mind that some processes can finish sooner, some can finish later
            // good use is when you have tasks dependent on network latency and you want
            // them executed asynchronously (such as uploading multiple files to an ftp or 
            // synchronizing of something that's being done over network

            // after you're done, kill the process so it doesn't become a zombie

            posix_kill(getmypid(), 9); // not the most elegant solution, and can fail
        }
    }
}
person N.B.    schedule 07.04.2011

Вы не имеете дело с PID после вызова pcntl_fork . Ваши вилки разветвляются, потому что цикл продолжает выполняться и разветвляться.

Если вы не пытаетесь создать локализованную форк-бомбу, вы вероятно не хотите, чтобы ваши форки разветвлялись.

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

Полная спекуляция.

Возможно, вы захотите рассмотреть другой способ выполнения параллельной обработки с помощью PHP. Использование Gearman в качестве рабочей очереди с несколькими процессами — мое любимое решение.

person Charles    schedule 07.04.2011