diff --git a/reference/pthreads/examples.xml b/reference/pthreads/examples.xml new file mode 100644 index 0000000000..62916a100f --- /dev/null +++ b/reference/pthreads/examples.xml @@ -0,0 +1,192 @@ + + + + + &reftitle.examples; + +
+ + Hello World Example + This HelloWorld example demonstrates how simple it is to define and execute Threads in PHP applications. + world = $world; + } + + public function run(){ + return sprintf("Hello %s", $this->world); + } + } + $thread = new HelloWorld("World"); + if ($thread->start()) { + printf("Thread #%lu says: %s\n", $thread->getThreadId(), $thread->join()); + } + ?> + ]]> + +
+ +
+ + Synchronization + The purpose of PHP is to generate content, having Threading in the toolbox makes more content available. But content is a relative subject, for this reason good control is needed over when a Thread is allowed to execute, or indeed, forced to wait. + For example, a meta search engine may have to carry out the following: + + Initiate a search with primary source of data + Log results of API usage for statistical analysis + Cache results to limit external API usage + Query local databases to generate page content - recent searches etc + Log results of local databse usage, HTTP usage, cache usage and possibly fall back to secondary source and goto 2; + Generate content ( HTML ) from API output, xml/json etc + Send content to client + + In a multi-threaded design, the Thread delegated Task 2 cannot possibly run until Thread 1 has returned a result. + In an extreme design, where each Task is allocated a Thread, Threads 2,3,4,5 and even 6 can all be run concurrently, but they all depend on Thread 1 returning content. + pthreads includes an easy to use way to synchronize when Threads are allowed to execute, or forced to wait, to allow flexible, powerful multi-threading wether being used for a Search Engine or Administration ( ie. cron jobs ). + params = $params; + } + + /* ... */ + + public function run(){ + /* do some admin possibly here, maybe lookup local caches, check if the client is googlebot etc */ + if ($this->ensureAvailabiilty()) { + $this->notify(); + + return $this->resultSet(); + } + } + } + + class Task2 extends Thread { + public function __construct($task1, $params){ + $this->task1 = $task1; + $this->params = $params; + } + + /* ... */ + + public function run(){ + $task1 = Thread::getThread($this->task1); + if ($task1->wait()) { + $this->createLogs(); + } + } + } + + $tasks = array(); + + $tasks[0]=new Task1($_POST); + $tasks[1]=new Task2($tasks[0]->getThreadId(), $_POST); + /* ... */ + + foreach ($tasks as $id => $task) { + $task->start(); + } + + /* ... */ + ?> + ]]> + Using the wait/notify mechanism included in pthreads hides the complexity of using Mutex and Condition Variables to synchronize Threads, greatly simplifies readability and more importantly maintainability of an idea or implementation. + +
+ +
+ + Mutex and Condition Variables + pthreads allows direct access to ( a subset of ) both of these features. The programmer should take care to destroy Mutex and Condition Variable handles that are no longer required for their logic. + Mutex and Condition Variables are not destroyed on behalf of the programmer like other resources in PHP, as this would limit their usefulness in the context of multi-threading in SAPI environments. + They are easily stored and passed around as they are represented as long numbers. Mutex and Condition Variables persist once allocated until they are explicitly destroyed. + + ]]> + + The snippet above shows a PHP script sending it's final broadcast to the Threads it has created and cleaning up the Condition Variable it created and used for the broadcast. + Other Threads that were waiting for a signal on $finished were using $signals - waiting for a signal always requires a Mutex - and as the Condition Variable is no longer valid, the accompanying Mutex is also destroyed. + + + Before the programmer attempts to use Condition Variables they should have knowledge of "Spurious Wakeups" as allowed for in the Posix Threads specification upon which pthreads is built. + + A brief exaplanation of the problem is as follows: + + + A call to Cond::wait may return before the Condition Variable recieves a legitimate signal as a result of another context calling Cond::signal or Cond::broadcast. + Because of this behaviour, a call to wait for a signal on a Condition Variable must check a predicate ( usually a boolean value ) upon returning from the call to Cond::wait. This eliminates the risk of Spurious Wakeups. + + + +
+ +
+ + Thread Members + The members of a Thread can be of any type that PHP supports the serialization of, including programmer declared classes. + In the case where a Thread contains members that are of a programmer declared type ( class ), the programmer must include the declaration using Thread::__prepare magic method. + Thread::__prepare method is executed by pthreads in the newly created context, before the newly created context executes Thread::run. This results in correct deserialization of the programmer declared type in the new context. + myType = $myType; + } + + public function run(){ + if (method_exists($this->myType, "myMethod")) { + + } + } + } + require_once("/path/to/inc.php"); + /* ... */ + $my = new Inc(); + /* ... */ + $example = new ExampleThread($my); + if ($example->start()) { + /* ... */ + } + ?> + ]]> + + In the example above, /path/to/inc.php declares a class, as defined by the programmer. The programmer includes the declaration in the global scope before passing an instance of the object to an instance of ExampleThread. + The instance of ExampleThread is able to manipulate the object and execute member functions having included the declaration using __prepare magic. + + +
+
+ +