I've been playing around with the (not new) idea of introducing threads
into PHP userland (maybe something to think about havin in PHP6?). What
came out of it is available at [1], offering an object oriented API (in
comparison to PECL/threads [2]).

Threads would quite likely come in handy in the following situations:
- GTK-PHP thin network client application "polling" a socket for events
  (e.g., IRC client)

- Multiple simultaneous connections to slow services (for instance,
  think of whois + check multiple domain names).

Both of these examples could be realized using fork() or
socket_select(), though the first is not portable and the latter
produces unnecessary overhead.

Maybe someone here would like to pick up on this idea or give some
directions to what would have to be done to make this actually work
dependably. I'm experiencing the same issues as with PECL/threads -
variable "confusion" (local function arguments with same names in two
threads affect each other), Engine unstability (Warning: ... in ... on
line -18182899), but could get a couple of samples[3] to work quite
well.

Maybe the userland API could be adopted by PECL/threads? Is anyone still
working at this or was development given up?

1] http://sitten-polizei.de/php/threads-0.1alpha.tar.gz
2] http://cvs.php.net/cvs.php/pear/PECL/threads
3] http://sitten-polizei.de/php/threads/tests/?file=mythread.php
   http://sitten-polizei.de/php/threads/tests/?file=timer.php
   http://sitten-polizei.de/php/threads/tests/?file=simple.php
   http://sitten-polizei.de/php/threads/tests/?file=calendar.php
   etc.

- Timm
Threads for PHP
========================================================================
$Id$

1. API:
-------
The thread API for PHP was designed to assemble that of Java (see
API documentation for lang.Thread).

2. Usage:
---------
To create a thread, subclass the Thread class (defined in threads.c)
and overwrite its run() method. Put any code to be executed into this
function.

3. Basic example:
-----------------
<?php
  class MyThread extends Thread {
    public function run() {
      print("<thread> init\n");
      sleep(4);
      print("<thread> finished\n");
    }
  }
  
  $m= new MyThread();
  $m->start();
  
  // Wait for thread
  print("<main>\n");
  sleep(5);
  print("<main> done\n");
?>

For more examples, see the tests/ subdirectory.

3.1. Example scripts output:
----------------------------

mythread.php (the sourcecode above)
| <thread> init
| <main>
| <thread> finished
| <main> done

timer.php (schedule reminder to alert in five seconds from now)
| About to schedule task.
| Task scheduled at 18:33:59.
| 18:33:59
| 18:34:00
| 18:34:01
| 18:34:02
| 18:34:03
| Reminder: It's now 18:34:04!
| 18:34:04
| Done.

calendar.php (schedule three tasks to alter in 2, 5 and 8 seconds from now)
| About to schedule tasks.
| Tasks scheduled at 18:34:35.
| 18:34:35
| 18:34:36
| Reminder: It's now 18:34:37, Buy food
| 18:34:37
| 18:34:38
| 18:34:39
| Reminder: It's now 18:34:40, Cook it
| 18:34:40
| 18:34:41
| 18:34:42
| Reminder: It's now 18:34:43, Meal done
| 18:34:43
| 18:34:44
| Done.

consumer_producer.php (demonstrate wait/notify)
| >>> Producer put 0 into resource #0
| <<< Consumer got 0 from resource #0
| >>> Producer put 1 into resource #0
| <<< Consumer got 1 from resource #0
| >>> Producer put 2 into resource #0
| <<< Consumer got 2 from resource #0
| >>> Producer put 3 into resource #0
| <<< Consumer got 3 from resource #0
| >>> Producer put 4 into resource #0
| <<< Consumer got 4 from resource #0
| >>> Producer put 5 into resource #0
| <<< Consumer got 5 from resource #0
| >>> Producer put 6 into resource #0
| <<< Consumer got 6 from resource #0
| >>> Producer put 7 into resource #0
| <<< Consumer got 7 from resource #0
| >>> Producer put 8 into resource #0
| <<< Consumer got 8 from resource #0
| >>> Producer put 9 into resource #0
| <<< Consumer got 9 from resource #0
| ### Done

hostcheck.php (NOT WORKING CORRECTLY, threads do not get joined)
| ---> Trying test.edu:443
| ---> Trying php3.de:25
| ---> Trying blup.blop:1010
| ---> Trying localhost:80
| ---> Trying localhost:6100
|      >> -ERR test.edu:443 [-1078991188]: getaddrinfo: null result pointer
|      >> +OK php3.de:25
|      >> -ERR blup.blop:1010 [-1079200356]: getaddrinfo: null result pointer
| ===> Destruct thread for blup.blop:1010
|      >> +OK localhost:80
| ===> Destruct thread for localhost:80
|      >> -ERR localhost:6100 [61]: Connection refused
| ===> Destruct thread for localhost:6100
| DONE
| ===> Destruct thread for test.edu:443
| ===> Destruct thread for php3.de:25

The ideas for the examples were taken from
http://java.sun.com/docs/books/tutorial/essential/threads/index.html

4. Problems:
------------
- Mysterious things happen at the moment: E.g., global variables dissapear,
  fatal errors in run() lead to a failed longjmp() and therefore to "Abort
  trap", join() doesn't return the correct value (mostly returning NULL:
  I guess this has to do with the thread's EG(retval_ptr_ptr) overwriting
  one another(?)).
  
- This does NOT work with ZTS, there are segfaults all over Zend Engine (2)
  probably due to my complete lack of knowlegde of TSRM. In php_threads_run
  after the first call to TSRMLS_FETCH(), all of the *_init_globals functions 
  are called over, initializing stuff and wrecking all of the EG() stuff, 
  leading to the beloved "Segmentation fault (core dumped)".
  
- tests/hostcheck.php won't work for some reason still to be figured out.

- Local method variables with same names get mixed up and interfere with
  each other. In the examples, private member variables are used to 
  achieve a workaround
  
- Objects are thrown away by the garbage collector since in the main thread,
  they're not needed. Workaround is to put these into member arrays.

- Only pthread is supported (see http://cvs.php.net/co.php/pear/PECL/threads/
  --> threadapi.c and TSRM/TSRM.c for how to make this work with other thread
  libraries).

4.1. TODO:
----------
- Figure out or have someone tell me if there is a glimpse chance of this
  ever working (as PECL/threads doesn't, either) or if I chose the completely
  wrong approach(?)
  
5. Conclusion:
--------------
This was a first-shot kind of thing, I didn't expect it to work at all.
Surprisingly, the timer examples work wonderfully, as does the simplethread
demo and the Consumer/Producer thing, nevermind the necessary sleep to let
the threads finish.

Therefore, I'm "releasing" this. Maybe someone thinks this is cool, has far
more understanding of the Engine/TSRM/Threads and C programming in general
than I do and can get some ideas.

6. Build environment:
---------------------
# uname -a
FreeBSD friebes.net 4.7-STABLE FreeBSD 4.7-STABLE #8: Sat Oct 26 19:38:23 CEST 2002
[EMAIL PROTECTED]:/usr/obj/usr/src/sys/GENERIC  i386

# ~/devel/php/php5/sapi/cli/php -v
PHP 5.0.0-dev (cli) (built: Mar  5 2003 17:08:05)
Copyright (c) 1997-2003 The PHP Group
Zend Engine v2.0.0-dev, Copyright (c) 1998-2003 Zend Technologies

# ~/devel/php/php5/sapi/cli/php -m
[PHP Modules]
ctype
curl
ftp
gettext
iconv
imap
ldap
mysql
openssl
pcntl
pcre
posix
session
sockets
standard
sybase_ct
sysvsem
sysvshm
threads
tokenizer
xml
xslt
zlib

[Zend Modules]

# ident /usr/include/pthread.h 
/usr/include/pthread.h:
     $FreeBSD: src/include/pthread.h,v 1.20.2.2 2001/03/04 22:38:48 alfred Exp $

7. Configuration:
-----------------
Place the files into ${php-top-srcdir}/ext/threads, run buildconf in 
${php-top-srcdir}, and add --enable-threads to your configure line.

After make, the following should show up in phpinfo():

# ~/devel/php/php5/sapi/cli/php -i|grep 'Threads ext'
Threads extension => enabled

Use #define THREADS_DEBUG 1 to control debugging (or simply start PHP with
2>/dev/null :)).

<EOF>

-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to