GNU Pthを使って、PHPでユーザスレッドを実現する

のをやってみた。もうちょっと作り込んでから、と思ったけど、まあまあまともに動くので先に公開。

次のようなスクリプトがさくさく動いちゃうよ!

<?php
function echoing($fd) {
    echo "connection established\n";
    while (!feof($fd)) {
        fwrite($fd, fgets($fd));
    }
    fclose($fd);
    echo "connection closed\n";
}

$ssock = stream_socket_server('tcp://127.0.0.1:8000');
assert($ssock !== false);

for (;;) {
    $csock = stream_socket_accept($ssock);
    thread_create('echoing', $csock);
    fclose($csock);
}

?>

ビルド方法

freehg.org 上の Mercurial レポジトリ http://freehg.org/u/moriyoshi/php-threading/ から clone したものを PHP のソースツリーの ext/threading に突っ込んで
1. レポジトリに含まれる function_name_redefinition_fix.diff.patch を適用 (-p0)
2. ソースツリーのトップで ./buildconf
3. 次の変数とパラメータで PHP をビルド

LDFLAGS="`pth-config --libs --ldflags`" \
CPPFLAGS="`pth-config --cflags` -DPTH_SYSCALL_SOFT=1" \
./configure --with-tsrm-pth=pth-config \
--enable-maintainer-zts \
$@

3. make && make install

制限事項

  1. まだ発見されていないバグがたくさんあります。
  2. Windowsでは動きません。
  3. 現在の実装ではスレッドを作る度に、スレッドの生死に関係なく少しづつメモリを食いつぶしていきます。(これはそのうち直します)
  4. 基本的にスレッドのくせにコンテキストをほとんど共有できないので、プロセスみたいになっています。
  5. 定義済みの関数とクラスはサブスレッドに継承されます。
  6. スレッドにデータを渡すには、スレッドのエントリ関数に引数として与えるしかありません。
  7. スレッドのエントリ関数に渡されたデータは例外なく複製が行われます。
  8. 参照が含まれるコンテナ (配列、オブジェクト) を渡すとエラーになります。
  9. 渡すことのできるリソースの種類が限定されています。
  10. ファイルハンドルとソケットを渡す場合、ハンドルが複製されます。