php pthreads锁定变量

Але*_*кин 1 php pthreads

我现在熟悉php线程.找到工人和收集classess相当有趣和方便.但我无法找到如何锁定变量以进行更改

class job extends Collectable {
  public static $count = 0;
  public $url;
  private $file = "outfile.txt";
  public function __construct($url){
    // init some properties
    $this->url = $url;

  }
  public function run(){
    // do some work
    //$this->val = $this->val . file_get_contents('http://www.example.com/', null, null, 3, 20);
    //echo $this->url;
    $data = explode("|", $this->url);
    $vars = GetServerVars($data[0], $data[1]);
    $this->lock();
    self::$count++;
    $this->unlock();
    echo "current_count: ".self::$count."\n";
    $this->setGarbage();
  }
}
Run Code Online (Sandbox Code Playgroud)

由于某些原因,这不起作用,我连续几次得到1,2,3,4号.所以self :: $ count不会连续增加.为什么会这样?在pthreads中纠正锁变量的方法是什么?谢谢!

Joe*_*ins 5

静态变量是线程本地的,因此您不能将静态变量用作共享计数器.

下面的代码将创建一个愚蠢的线程数(100),每个线程接受一个Threaded结果对象和一个int $value.

如果$value是偶数,我们认为它是成功的,否则就是失败; 我们执行适当的函数来安全地增加共享计数器.

<?php
class Results extends Threaded {

    public function addError() {
        return $this->synchronized(function(){
            return $this->error++;
        });
    }

    public function addSuccess() {
        return $this->synchronized(function(){
            return $this->success++;
        });
    }

    private $error;
    private $success;
}

class Process extends Thread {

    public function __construct(Results $results, int $value) {
        $this->results = $results;
        $this->value = $value;
    }

    public function run() {
        if ($this->value % 2 == 0)
            $this->results->addSuccess();
        else $this->results->addError();
    }

    private $results;
    private $value;
}

$results   = new Results();
$processes = [];
$process   = 0;

do {
    $processes[$process] = 
        new Process($results, mt_rand(1, 100));
    $processes[$process]->start();
} while (++$process < 100);

foreach ($processes as $process)
    $process->join();

var_dump($results);
?>
Run Code Online (Sandbox Code Playgroud)

注意:这是PHP 7 + pthreads v3代码...不要将v2用于新项目

调用synchronized确保在调用上下文时没有其他上下文可以为同一对象输入同步块,这确保了synchronized块中提供的操作的安全性:

object(Results)#1 (2) {
  ["error"]=>
  int(49)
  ["success"]=>
  int(51)
}
Run Code Online (Sandbox Code Playgroud)

好奇的程序员现在可能会继续删除同步块,并且他们惊讶地发现输出是相同的.

原因是因为对象成员的操作是原子的 - 换句话说,递增和递减指令可以假定为原子.

你很难猜出哪些操作是原子的,所以不要.

假设是可怕的; 只要同步块中的代码比单个指令更复杂,您的代码就会对竞争条件开放.明智的做法是设置一个标准,说明如果你需要在任何数量的语句中使用原子性,它们应该在同步块中执行.