在C中使用pthread调用php函数

时间:2016-01-22 16:43:20

标签: php c multithreading thread-safety pthreads

我需要多线程一个PHP函数但是当我调用一个php函数时我得到这个错误“Safari无法打开页面” Safari can’t open the page “‎localhost/home.php” because the server unexpectedly dropped the connection. This sometimes occurs when the server is busy. Wait for a few minutes, and then try again.

我的php文件中有这些行

<?php
echo "Hello World","<br>";
open_thread("hello");

function hello() {
     echo "Hello World";
}

当我从hello中删除open_thread("hello");时,它只会输出此警告: Warning: open_thread() expects exactly 1 parameter, 0 given in /Users/username/Sites/home.php on line 3

当我调用其中有输出的C函数时,当我从函数服务器中删除输出并且什么都不显示时,也会发生这种情况。

此处出现问题pthread_join(tid, NULL);

这是我的C代码

PHP_FUNCTION(open_thread)
{

    zval *threaded_func;
    zend_string *func_name;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &threaded_func) != SUCCESS) {
        return;
    }


    if (Z_TYPE_P(threaded_func) != IS_NULL) 
    {
        if (!zend_is_callable(threaded_func, 0, &func_name TSRMLS_CC)) 
        {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "’%s’ is not a valid read callback", func_name);
            efree(func_name);
            RETURN_FALSE;
        }
        efree(func_name);
    }


    pthread_t tid;
    zend_printf("Starting..\n");
    pthread_create(&tid, NULL, (void *) threaded_func, NULL);
    pthread_join(tid, NULL);
    zend_printf("Finished\n");
}

问题
这是一个线程安全的问题吗?我该如何解决?

1 个答案:

答案 0 :(得分:1)

PHP可以构建为支持多线程SAPI - ZTS模式 - 然而,重要的是要意识到所使用的内存模型没有任何共享。

在无共享模型中,每个线程都有不同的解释器(编译器,执行器,所有模块全局,所有用户代码,整个批次)。

这意味着各种各样的事情:

  • 为线程A编译的代码不能由线程B执行。线程B必须从线程A复制代码,执行pass_two之类的操作并执行代码副本。
  • 从引用对象,资源或哈希表的线程A复制的代码可能(将)在没有适当准备和/或适当的对象处理程序的情况下中断。

简单地启动一个线程并尝试调用Zend注定会失败,因为它忽略了PHP的无共享特性。

新线程的流程必须类似于:

void routine(void *thing) {
    ts_resource(0);

    php_request_startup();

    /* do stuff */

    php_request_shutdown();

    ts_free_thread();
}
  • ts_resource:这会在新线程中初始化TSRM,反过来初始化一些Zend
  • php_request_startup:初始化所有内容的其余部分,其中包括所有模块的RINIT
  • php_request_shutdown:运行RSHUTDOWN,通常会清理
  • ts_free_thread:可选择免费,否则会在进程关闭时发生(当TSRM最终关闭时)

实际上,示例流也会失败,如果它试图调用由(for)另一个线程编译的用户代码:在请求启动之后,在您可以调用用户代码之前,您需要先将代码复制到当前上下文中

在pthreads扩展源中可以找到有关如何在现实世界中工作的详细信息。