在pthreads的介绍中,我读到:
当程序员调用Thread::start时,会创建一个新线程,初始化一个PHP解释器上下文,然后(安全地)对其进行操作,以镜像调用::start的上下文。
在本文的后面,分割错误问题得到了解决。给出了分段故障的示例:
class W extends Worker {
public function run(){}
}
class S extends Stackable {
public function run(){}
}
/* 1 */
$w = new W();
/* 2 */
$j = array(
new S(), new S(), new S()
);
/* 3 */
foreach ($j as $job)
$w->stack($job);
/* 4 */
$j = array();
$w->start();
$w->shutdown();
上面的例子总是会出错;步骤1-3是完全正常的,但在Worker启动之前,堆叠的对象会被删除,导致Worker被允许启动时出现segfault。
问题是:
- 当调用
start()
时,启动新线程的整个上下文是否复制到新线程中,或者仅在解释器看到对旧上下文变量的引用时?换句话说,在调用start()
之前保持refcounts>0就足够了吗 - 对
Stackable
数组实体的引用是否应该存储在Worker
对象中,以便在覆盖$j
后它们的refcount仍然为1,并且不会发生segfault
1)线程启动时,会复制整个上下文。在工作线程实际执行堆叠的对象之前,必须保持refcounts>0。
2) PHP中内置在变量中的引用计数从未为多线程做好准备,许多api函数会递减和递增引用计数,并且没有机会同步(锁定)。出于这个原因,您负责维护对任何对象的引用,该对象将由另一个线程执行。
通过使用pthreads提供的Pool
抽象,可以回避这些令人讨厌但不可避免的事实。它以适当的方式为您维护参考资料。
http://php.net/Pool