php pthreads 锁定变量
php pthreads locking variable
我目前正在熟悉 php 线程。发现 worker 和 collectable classes 非常有趣和方便。但是我找不到如何锁定变量以进行更改
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();
}
}
出于某种原因,这不起作用,我连续几次得到数字 1、2、3、4。所以 self::$count 不会连续递增。为什么会发生这种情况?以及在pthreads 中更正锁变量的方法是什么?谢谢!
静态变量是线程本地的,因此您不能将静态变量用作共享计数器。
下面的代码将创建一个愚蠢的线程数 (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);
?>
注意:这是 PHP 7 + pthreads v3 代码...不要将 v2 用于新项目
调用synchronized
确保在调用上下文时没有其他上下文可以进入同一对象的同步块,这确保了同步块中提供的操作的安全性:
object(Results)#1 (2) {
["error"]=>
int(49)
["success"]=>
int(51)
}
好奇的程序员现在可能会继续删除同步块,并且令他们惊讶的是会发现输出是相同的。
这是因为对对象成员的操作是原子的——换句话说,递增和递减指令可以假定为原子的。
您很难猜测哪些操作将是原子操作,所以不要。
假设很糟糕;一旦同步块中的代码比单个指令更复杂,您的代码就会对竞争条件开放。明智的做法是设置一个标准,说明如果您需要对任意数量的语句执行原子性,它们应该在同步块中执行。
我目前正在熟悉 php 线程。发现 worker 和 collectable classes 非常有趣和方便。但是我找不到如何锁定变量以进行更改
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();
}
}
出于某种原因,这不起作用,我连续几次得到数字 1、2、3、4。所以 self::$count 不会连续递增。为什么会发生这种情况?以及在pthreads 中更正锁变量的方法是什么?谢谢!
静态变量是线程本地的,因此您不能将静态变量用作共享计数器。
下面的代码将创建一个愚蠢的线程数 (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);
?>
注意:这是 PHP 7 + pthreads v3 代码...不要将 v2 用于新项目
调用synchronized
确保在调用上下文时没有其他上下文可以进入同一对象的同步块,这确保了同步块中提供的操作的安全性:
object(Results)#1 (2) {
["error"]=>
int(49)
["success"]=>
int(51)
}
好奇的程序员现在可能会继续删除同步块,并且令他们惊讶的是会发现输出是相同的。
这是因为对对象成员的操作是原子的——换句话说,递增和递减指令可以假定为原子的。
您很难猜测哪些操作将是原子操作,所以不要。
假设很糟糕;一旦同步块中的代码比单个指令更复杂,您的代码就会对竞争条件开放。明智的做法是设置一个标准,说明如果您需要对任意数量的语句执行原子性,它们应该在同步块中执行。