PHP多线程pthreads-v3-线程同步wait-notify的使用

1.什么是线程同步

线程同步就是指线程按照先后顺序对内存进行操作,以避免多个线程同时操作内存的情况。

2.线程同步的实现方法有哪些

1.临界区、2.互斥量、3.信号量、4.事件对象

3.PHP多线程中同步的实现方式

v3的同步主要用synchronized方法,昨天的 PHP多线程pthreads-v3-互斥锁的使用 就是用了 synchronized 写了一个互斥量的例子,互斥量对于不满足条件的线程没有做到阻塞等待,所以该线程也就没能执行它的任务。今天我们通过wait和notfiy来实现线程阻塞等待到通知同步的过程。

4.例子简介

首先对于继承自threaded的类,其成员变量如果是数组类型,实质会转换成Volatile对象。 (注意点)

我们的例子是按奇偶顺序初始化100个线程,奇数是UI线程,偶数是Worker线程。UI线程进行渲染操作的前提条件就是对应的Worker线程需要处理完数据才能执行。于是UI线程对于没有处理完的Worker线程会阻塞,直到Woker线程处理完数据后notify(通知)唤醒相应的UI线程进行渲染操作。

<?php

class ShareData extends Threaded
{
    private $tids = [];
    private $tids_reverse = [];
    private $finish = [];

    public function __construct()
    {

    }

    public function pushTid($perfix, $tid)
    {
        $this->tids[$tid] = $perfix;
        $this->tids_reverse[$perfix] = $tid;
        $this->finish[$tid] = false;
    }

    public function getTidsLength()
    {
        return count($this->tids);
    }

    public function setStatusByTid($tid, $status)
    {
        $this->finish[$tid] = $status;
    }

    public function getTids($reverse = false)
    {
        return !$reverse ? $this->tids : $this->tids_reverse;
    }

    public function getStatusByPrefix($perfix)
    {
        return $this->finish[$this->tids_reverse[$perfix]];
    }

    public function getPrefixByTid($tid)
    {
        return $this->tids[$tid];
    }

}

class MyThread extends Thread
{
    public function __construct(ShareData $data)
    {
        $this->data = $data;
        $this->start();
    }

    public function run()
    {
        $i = $this->data->getTidsLength();

        $prefix = ($i % 2 == 0 ? 'work' : 'ui') . $i;

        $tid = $this->getThreadId();

        $this->data->pushTid($prefix, $tid);

        $this->data->getTids()[$tid];

        $this->synchronized(function ($thread, $prefix, $tid) {
            if (strpos($prefix, 'ui') !== false) {
                $id = ((int)substr($prefix, 2)) - 1;

                $woker = 'work' . $id;

                while (!$thread->data->getStatusByPrefix($woker)) {
                    echo '开始阻塞' . $this->data->getPrefixByTid($tid) . PHP_EOL;

                    sleep(1);

                    $thread->wait();

                    echo '开始执行' . $this->data->getPrefixByTid($tid) . PHP_EOL;
                }
            } else {
                echo '开始执行' . $thread->data->getPrefixByTid($tid) . PHP_EOL;

                sleep(4);

                echo '执行完毕' . $thread->data->getPrefixByTid($tid) . PHP_EOL;

                $thread->data->setStatusByTid($tid, true);

                $thread->notify();
            }

        }, $this, $prefix, $tid);
    }
}

$shareData = new ShareData();

for ($i = 0; $i < 100; $i++) {
    $threads[$i] = new MyThread($shareData);
}

for ($i = 0; $i < 100; $i++) {
    $threads[$i]->join();
}

ui线程在worker线程执行完之前会阻塞等待
当worker线程执行完毕后,对应的ui线程就会被唤醒执行。
最终,ui线程和worker线程的协同配合完成了数据的处理。
如无特殊说明,文章均为本站原创,转载请注明出处。如发现有什么不对的地方,希望得到您的指点。

发表评论

电子邮件地址不会被公开。 必填项已用*标注