Zbigniew ‘zibi’ Jarosik Ecie-pecie o wszechświecie
  • PHP (pseudo)Threads

    Brakuje mi w PHP wielowątkowości. Jakoś autorom nie jest pilno do tego a czasem by się przydało.

    Z potrzeby chwili powstało coś takiego:

     
    class Thread
    {
        private $token=false;
        private $semaphore=false;
        private $data=array();
     
        function __construct()
        {
            $data=array();
            $SHM_KEY = ftok(__FILE__, chr( 4 ) );
     
            $this->semaphore = sem_get($SHM_KEY,1);
            $this->token =  shm_attach($SHM_KEY, 1024, 0666);
     
            @shm_remove($this->token);
            shm_attach($this->token);
            @shm_put_var($this->token,1,$data);
        }
        function __call($method,$params)
        {
            if(substr($method,0,3)==='___')
            {
                $pid=pcntl_fork();
     
                if($pid)
                {
                    $method=substr($method,3);
                    @call_user_func_array(array(&$this,$method),$params);
                }
            }
        }
        function __sleep()
        {
        }
        function __wakeup()
        {
        }
        function __set($key,$value)
        {
            if(substr($key,0,3)==='___')
            {
                $key=substr($key,3);
                sem_acquire($this->semaphore);
     
                $data=@shm_get_var($this->token,1);
                $data[$key]=$value;
     
                @shm_put_var($this->token,1,$data);
     
                sem_release($this->semaphore);
            }
            $this->data[$key]=$value;
     
            return $value;
        }
        function __get($key)
        {
            if(substr($key,0,3)==='___')
            {
                $key=substr($key,3);
                $data=@shm_get_var($this->token,1);
     
                if(isset($data[$key]))
                {
                    $ret=$data[$key];
                    $this->data[$key]=$ret;
                }
                else
                {
                    $ret=$this->data[$key];
                }
            }
            else
            {
                $ret=$this->data[$key];
            }
     
            return $ret;
        }
    }

    Korzysta się z tego dość prosto.
    Przykład klasy wykorzystującej wątkowanie:

     
    class Thread_Test extends Thread
    {
        function loop1()
        {
            for($this->___i1=0;true;$this->___i1++)
            {
                sleep(3);
            }
        }
        function loop2()
        {
            for($this->i2=0;true;$this->i2++)
            {
                sleep(2);
            }
        }
        function loop3()
        {
            for($this->i3=0;true;$this->i3++)
            {
                echo "loop1: {$this->___i1} loop2: {$this->___i2} loop3: {$this->___i3} loop4: {$this->___i4}\n";
                sleep(1);
            }
        }
        function loop4()
        {
            for($this->___i4=0;true;$this->___i4++)
            {
            }
        }
    }

    i właściwe wywołanie:

     
    $t = new Thread_Test();
     
    $t->___loop1();
    $t->___loop2();
    $t->___loop4();
    $t->loop3();
     
    while(1)
    {
    	sleep(1);
    	echo "MAIN {$t->___i1} \n";
    }

    Jak widać ;P aby wywołać metodę jako osobny wątek dodajemy przed jej nazwą trzy znaki podkreślenia, np $t->___waitLongTime(); To samo tyczy się zmiennych. Zmienne zapisane tradycyjnie ($t->zmienna) są zmiennymi lokalnymi wątku, zmienne z trzema znakami podkreślenia ($t->___zmienna) są zmiennymi współdzielonymi w klasie, dostępnymi dla wszystkich wątków.

    Dostęp do zmiennych współdzielonych jest bardzo wolny. Spowodowane jest to koniecznością synchronizowania zapisów do zmiennych.

    1 Comment