<?php
$v = new Volatile;
$t = new class($v) extends Thread
{
function __construct(Volatile $v)
{
$this->v = $v;
}
function run()
{
$this->v[] = "str";
}
};
$t->start(); $t->join();
var_dump($v);
转储:
object(Volatile)#1 (1) {
[0]=>
string(3) "str"
}
如果我这样做:
<?php
$v = new Volatile;
$t = new class($v) extends Thread
{
function __construct(Volatile $v)
{
$this->v = $v;
}
function run()
{
$this->v[] = ["array" => ["test"]];
}
};
$t->start(); $t->join();
var_dump($v);
错误:
致命错误:未捕获RuntimeException:pthreads检测到尝试 连接到已经被销毁的对象
如何修复此代码?
答案 0 :(得分:0)
TLDR快速解决方案:
键入强制转换数组以在内存中以不同方式初始化
$this->v[] = (array) ["array" => ["test"]];
工作示例:
class My extends Thread {
public function run() {
$arr = array(
[ "foo" => "bar" ],
[ "someInt" => 3 ],
7 => "seven",
"dog" => "jack russell"
);
$this->result = $arr; // Result is Volatile object
$this->result = (array) $arr; // Result is Array()
}
}
$th = new My(); $th->start(); $th->join();
var_dump($my->result); // Array, works
说明:
您的问题是由于在生成的线程和主程序之间共享内存的困难。
新线程运行自己的&#34;私有&#34;内存分配,远离主程序。线程利用的内存不能由父线程访问。当线程结束时,垃圾收集器清理混乱;挥发性物体被破坏;所以你刚设置的数据不再存在,因此错误。)
那么为什么你能用上面的方式写使用Strings而不是Arrays?因为PHP 在幕后初始化不同的变量类型的方式!我怀疑初始化String(或整数)是由PHP在主堆中完成的,因此可以全局访问。数组是不同的;它们是更复杂的引用类型,并以不同方式初始化。您对&#34; str&#34;的陈述如果你首先初始化它们,也会使用整数(见下文)!在内部线程中,数组作为易失性对象处理。
虽然语法上相似,但这两个语句是以不同的方式初始化和寻址内存:
// What we are saying here is:
// $this->v[] points to a Volatile Object { ["array" => ["test"]] };
$this->v[] = ["array" => ["test"]]; // *contents* of the array is only available to the thread via Volatile {...} and only exists while the thread is running
然而:
// What we are saying here is:
// $this->[] Should be initialized as "str" (possibly in the main heap)
$this->v[] = "str"; // *contents* of $this->v[] available to both threads and remains in memory after the thread completes
类似于你的&#34; str&#34;例如,以下使用Integer类型也可以工作:
class My extends Thread {
public $result = 1;
public function run() {
$this->result = 3; // Works
}
}
$th = new My(); $th->start(); $th->join();
var_dump($my->result); // int(3), works
你想要的是为作业/线程提供内存地址,它应该将其结果转储为Array类,而不是Volatile。 (而不是尝试在线程内部创建一个内存地址,并将指向该地址的指针返回给父线程,这当然永远不会工作,因为线程完成时擦除了该内存的内容)