gpt4 book ai didi

php - pthread 线程对象重置它们的状态

转载 作者:可可西里 更新时间:2023-11-01 12:28:34 24 4
gpt4 key购买 nike

最近使用扩展 pthreads ,我发现了一个异常。我有一个带有内部状态的简单对象:

class Sum {
private $value = 0;
public function add($inc) { $this->value += $inc; }
public function getValue() { return $this->value; }
}

现在我创建了一个 Thread 类来处理这个对象:

class MyThread extends Thread {
private $sum;

public function __construct(Sum $sum) {
$this->sum = $sum;
}

public function run(){
for ($i=0; $i < 10; $i++) {
$this->sum->add(5);
echo $this->sum->getValue() . " ";
}
}
}

在我的主函数中,我创建了一个 Sum 对象,将其注入(inject)线程并启动它:

$sum = new Sum();
$thread = new MyThread($sum);
$thread->start();
$thread->join();
echo $sum->getValue();

我预计结果为 50,因为线程必须将值递增 10 次,每次递增 5。但我得到了 0!

更奇怪的是,失败的不是同步回主线程,而是线程似乎在途中忘记了它的内部状态:run() 方法中的 echo 输出不是预期的 5 10 15 20 25 30 35 40 45 50,而是 0 0 0 0 0 0 0 0 0 0。没有人干扰线程 - 为什么它不保留其状态?


旁注:如果我不启动线程而是直接在主线程中调用 run() 方法 ($thread->run();),结果仍然是相同的。但是,如果我现在删除类声明中的 extends Thread,它会完美运行并返回预期的 5 10 15 20 25 30 35 40 45 50

最佳答案

任何不是从 pthreads 定义派生的对象都将在将其设置为从 pthreads 派生的对象的成员时序列化。

像 += 和 [] 这样的操作在内部使用指针,序列化与其他对象的指针不兼容。在介绍页面的手册中,它指出任何打算由多个上下文操作的对象都应该扩展 Stackable、Thread 或 Worker,例如

<?php
class Sum extends Stackable {
private $value = 0;
public function add($inc) { $this->value += $inc; }
public function getValue() { return $this->value; }
public function run(){}
}

class MyThread extends Thread {
public $sum;

public function __construct(Sum $sum) {
$this->sum = $sum;
}

public function run(){
for ($i=0; $i < 10; $i++) {
$this->sum->add(5);
echo $this->sum->getValue() . " ";
}
}
}

$sum = new Sum();
$thread = new MyThread($sum);
$thread->start();
$thread->join();
echo $sum->getValue();
?>

如果 Sum 不使用指针,您可以选择在连接后从线程对象中检索引用。

这些都是简单的操作,不需要同步。唯一应该同步的时间是当您计划等待一个对象或通知一个对象时。

与 pthreads 捆绑在一起的对象非常适合这种环境,并且永远不会被序列化。

请务必阅读手册中的介绍和您希望使用的方法中的所有示例,以准确了解是什么,然后随时询问原因:)

我知道 PHP 用户不习惯做研究,但我们在这里挑战极限,您会发现有正确的方法和不正确的方法,其中大部分都记录在示例中,并且任何我不确定的东西都会在 SO 上从我这里提取出来,并最终找到文档的方式。

我不确定你给出的例子是否特别测试对象,但你提供的代码不需要是两个对象,也不应该是两个对象,请考虑以下几点:

<?php
class MyThread extends Thread {
public $sum;

public function run(){
for ($i=0; $i < 10; $i++) {
$this->add(5);

printf("%d ", $this->sum);
}
}

public function add($num) { $this->sum += $num; }
public function getValue() { return $this->sum; }
}

$thread = new MyThread();
$thread->start();
$thread->join();
var_dump($thread->getValue());
?>

如果您看到更多的功能并附上解释,可能会对您有所帮助,所以这里有一个与您的示例类似的示例:

<?php
class MyThread extends Thread {
public $sum;

public function __construct() {
$this->sum = 0;
}

public function run(){
for ($i=0; $i < 10; $i++) {
$this->add(5);

$this->writeOut("[%d]: %d\n", $i, $this->sum);
}

$this->synchronized(function($thread){
$thread->writeOut("Sending notification to Process from %s #%lu ...\n", __CLASS__, $thread->getThreadId());
$thread->notify();
}, $this);
}

public function add($num) { $this->sum += $num; }
public function getValue() { return $this->sum; }

/* when two threads attempt to write standard output the output will be jumbled */
/* this is a good use of protecting a method so that
only one context can write stdout and you can make sense of the output */
protected function writeOut($format, $args = null) {
$args = func_get_args();
if ($args) {
vprintf(array_shift($args), $args);
}
}
}

$thread = new MyThread();
$thread->start();

/* so this is synchronization, rather than joining, which requires an actual join of the underlying thread */
/* you can wait for notification that the thread is done what you started it to do */
/* in these simple tests the time difference may not be apparent, but in real complex objects from */
/* contexts populated with more than 1 object having executed many instructions the difference may become very real */
$thread->synchronized(function($thread){
if ($thread->getValue()!=50) {
$thread->writeOut("Waiting for thread ...\n");
/* you should only ever wait _for_ something */
$thread->wait();
$thread->writeOut("Process recieved notification from Thread ...\n");
}
}, $thread);

var_dump($thread->getValue());
?>

这在一些简单的示例中结合了一些更高级的功能,并进行了注释以帮助您。关于共享对象的主题,如果 Thread 对象包含其他线程或可堆叠对象所需的某些功能和数据,则传递 Thread 对象并没有错。您的目标应该是使用尽可能少的线程和对象来完成工作。

关于php - pthread 线程对象重置它们的状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14564234/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com