PHP多线程pthreads-v3-互斥锁的使用

1.关于pthreads v3的更新说明

v3版本是对PHP7进行的调整,移除了很多v2的方法和类,下面是移除的内容

Mutex,Cond, and Stackable

Threaded::lock and Threaded::unlock

Threaded::isWaiting

Threaded::from

Thread::kill

Thread::detach

Worker::isWorking

Threaded::getTerminationInfo

更多内容详见:https://github.com/krakjoe/pthreads

2.使用互斥锁的原因

当多个线程之间有共享的数据时,如果没有锁机制,那么多个线程可能同时获取某一个值,或者同时写入某一个值,导致最后某个值重复的读取或写入,这里有点像mysql事务中的幻读现象。下面我们来重现这种现象。

<?php

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

    public function run()
    {

        $val = file_get_contents('/tmp/info.txt');
        echo "读取:" . $val . "    tid:" . $this->getThreadId() . 
            date("   Y-m-d H:i:s", time()) . PHP_EOL;
        echo "成功写入了". file_put_contents('/tmp/info.txt', ++$val) . 
            "字节值为:$val" . "    tid:" . $this->getThreadId() . 
            date("   Y-m-d H:i:s", time()) . PHP_EOL;
    }
}

file_put_contents('/tmp/info.txt', 0);

$threads = [];

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

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

我们看到多个线程同时读取了同一个值,又同时写入了同一个值

3.如何使用互斥锁

pthreads v2有用到互斥量的方法来实现互斥锁,但是在v3中把互斥量等方法都干掉了。理由是:互斥量存在危险性可能产生死锁,可以用synchronized方法来代替。原文截图如下:

具体可以参考: https://blog.krakjoe.ninja/2015/08/a-letter-from-future.html

那么我们只能用synchronized的方法自己来实现一个互斥锁了,注意互斥锁本质也是 synchronized (同步)的一种。(补充:对于文件的写入追加独占锁,在多线程环境下对于并发的线程来说还是可以同时写入的,详见官方文档说明。)

<?php
class Mutex extends Threaded
{
    public function __construct($status = false)
    {
        $this->lock = $status;
    }


    public function getLock()
    {
        return $this->lock;
    }

    public function setLock($status)
    {
        $this->lock = $status;
    }
}

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

    public function run()
    {
        $this->synchronized(function($mutex) {
            if (!$mutex->getLock()) {
                $mutex->setLock(true);
                $val = file_get_contents('/tmp/info.txt');
                echo "读取:" . $val . "    tid:" .
                    $this->getThreadId() .
                    date("   Y-m-d H:i:s", time()) . PHP_EOL;
                echo "成功写入了". file_put_contents('/tmp/info.txt', ++$val) .
                    "字节值为:$val" . "    tid:" . $this->getThreadId() .
                    date("   Y-m-d H:i:s", time()) . PHP_EOL;
                $mutex->setLock(false);
            } else {
                echo 'Can not write' . PHP_EOL;
            }
        },$this->mutex);
    }
}

file_put_contents('/tmp/info.txt', 0);

$mutex = new Mutex();

$threads = [];

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

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

添加互斥量之后,多线程之间的操作就不存在同时读取或者写入的情况了。
如无特殊说明,文章均为本站原创,转载请注明出处。如发现有什么不对的地方,希望得到您的指点。

发表评论

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