user4672604
user4672604

Reputation:

Calling php functions using pthread in C

I need to multithread a php function but when I call a php function I get this error "Safari Can’t Open the Page" 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.

I have this lines in my php file

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

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

When I remove hello from open_thread("hello");, it simply outputs this warning: Warning: open_thread() expects exactly 1 parameter, 0 given in /Users/username/Sites/home.php on line 3

This also happens when I call C function which has output in it, when I remove outputs from the function server works and displays nothing.

The problem occurs here pthread_join(tid, NULL);

Here is my C codes

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");
}

The Question
Is it a thread safe issue? how do I fix it?

Upvotes: 1

Views: 393

Answers (1)

Joe Watkins
Joe Watkins

Reputation: 17168

PHP can be built to support multi threaded SAPI's - ZTS mode - however, it's important to realize that the memory model used is share nothing.

In a shared nothing model, each thread has a different interpreter (compiler, executor, all module globals, all user code, the whole lot).

This means various things:

  • Code compiled for thread A cannot be executed by thread B. Thread B must copy code from thread A, carry out something like pass_two and execute the copy of the code.
  • Code copied from thread A that references objects, resources, or hashtables, may (will) break without proper preparation and or appropriate object handlers.

Simply starting a thread and attempting to call into Zend is doomed to fail, as it ignores the shared nothing nature of PHP.

The flow of new threads needs to be something like:

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

    php_request_startup();

    /* do stuff */

    php_request_shutdown();

    ts_free_thread();
}
  • ts_resource: this initializes TSRM in the new thread, in turn initializing some of Zend
  • php_request_startup: initializes the rest of everything, among other things runs RINIT for all modules
  • php_request_shutdown: this runs RSHUTDOWN, generally cleans up
  • ts_free_thread: optionally free, would otherwise happen at process shutdown (when TSRM is finally shutdown)

As it is, the example flow would also fail, if it tries to call user code compiled by (for) another thread: After request startup and before you can call user code you need to copy the code into the current context first.

The fine detail of how any of this works in the real world can be found in the pthreads extension sources.

Upvotes: 1

Related Questions