首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么pcntl_fork()要复制PHP对象?

问为什么pcntl_fork()要复制PHP对象?
EN

Stack Overflow用户
提问于 2013-04-02 17:30:41
回答 2查看 1.3K关注 0票数 6

叉()的手册上说:

pcntl_fork()函数创建的子进程仅在PID和PPID方面与父进程不同。

然而,运行这个简单的测试让我感到惊讶:

代码语言:javascript
复制
class Foo
{
    public function bar()
    {
        if (pcntl_fork()) {
            echo spl_object_hash($this), PHP_EOL;
        } else {
            echo spl_object_hash($this), PHP_EOL;
        }
    }
}

(new Foo)->bar();

结果如下:

代码语言:javascript
复制
000000005ec7fd31000000003f0fcfe6
000000006b4cd5fc000000007fee8ab7

从文档中可以看出,我希望父进程和子进程共享相同的变量,特别是当fork()从对象内部生成时,我希望在两个进程中对对象的引用都是相同的。但上面的例子表明他们不是。

值得注意的是,这里没有克隆,看起来对象只是被复制了。如果我添加了一个__clone()函数,我可以看到它在分叉过程中没有被调用。

为什么变量/对象没有被两个进程共享,或者有什么好的主题读物?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-04-02 17:37:29

创建对象时不会计算对象哈希(可以这样想)。当第一次为对象调用spl_object_hash()时,将计算对象哈希。在你的例子中,这是后面的叉子。

进一步注意,在计算哈希时使用了一些随机性,因此不同的散列。

票数 1
EN

Stack Overflow用户

发布于 2013-04-02 18:03:49

对对象的引用在分叉进程中是相同的,因为对象在子进程的内存空间中的内存位置是相同的。

哈希计算为对象地址XOR --一个随机掩码(只生成一次),因为您可以在PHP源代码ext/spl/php_spl.c中读取

代码语言:javascript
复制
PHPAPI void php_spl_object_hash(zval *obj, char *result TSRMLS_DC) /* {{{*/
{
    intptr_t hash_handle, hash_handlers;
    char *hex;

    if (!SPL_G(hash_mask_init)) {
        if (!BG(mt_rand_is_seeded)) {
            php_mt_srand(GENERATE_SEED() TSRMLS_CC);
        }    

        SPL_G(hash_mask_handle)   = (intptr_t)(php_mt_rand(TSRMLS_C) >> 1);
        SPL_G(hash_mask_handlers) = (intptr_t)(php_mt_rand(TSRMLS_C) >> 1);
        SPL_G(hash_mask_init) = 1; 
    }    

    hash_handle   = SPL_G(hash_mask_handle)^(intptr_t)Z_OBJ_HANDLE_P(obj);
    hash_handlers = SPL_G(hash_mask_handlers)^(intptr_t)Z_OBJ_HT_P(obj);

    spprintf(&hex, 32, "%016x%016x", hash_handle, hash_handlers);

    strlcpy(result, hex, 33); 
    efree(hex);
}
/* }}} */

如果随机数生成器是在调用函数之前播种的,那么您将得到子进程和父进程的完全相同的输出。但在这种情况下,情况并非如此,每个进程都计算自己的种子。GENERATE_SEED的代码如下:

代码语言:javascript
复制
#ifdef PHP_WIN32
#define GENERATE_SEED() (((long) (time(0) * GetCurrentProcessId())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#else
#define GENERATE_SEED() (((long) (time(0) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#endif

正如您所看到的,种子依赖于进程ID,这对于父进程和子进程来说当然是不同的。

因此,不同的随机数产生器种子,不同的随机掩码,不同的哈希。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15770453

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档