线程安全那些事

引言

在上一篇文章,我们了解了什么是进程/线程,把多进程和多线程进行了对比,那通常所说的线程安全是什么呢?要想搞清楚这个概念,那么我们可以尝试逆向思维,如果线程不安全了,会是什么样的情形呢?我们以两个独立的线程为例,它们都继承了进程的共享变量,这些共享变量都有哪些呢?按照我的理解,这些共享变量可能是变量,数组,对象,甚至是数据库连接。一般情况下,线程会对这些共享变量有2个操作:读取和写入。下面是一个线程不安全的例子。

class NotThreadSafe extends \Thread {
    /**
     * @see https://www.programcreek.com/2014/02/how-to-make-a-method-thread-safe-in-java/
     */
    public function run() {
        return $this->getCount();
    }

    private static $counter = 0;
    public static function getCount() {
        return self::$counter++;
    }
}

当线程1在访问时,可能线程2尚未执行完成, 因此,返回到线程1 的值可能是未增加的值。

那么线程不安全带来的后果是什么呢?执行结果不可控,每次执行结果可能不一样,也就是无法重复执行同一部分含有有线程的代码,无法保证输入运算输出结果唯一。

什么是线程安全

现在,我们可以大致的理解了线程安全这个概念,所谓的线程安全,必定对同一个输入运算输出唯一的结果,并应当满足以下3个条件:
1. 多个线程同时访问时,其表现出正确的行为。
2. 无论操作系统如何调度这些线程, 无论这些线程的执行顺序如何交织(interleaving)。
3. 调用端代码无须额外的同步或其他协调动作。

PHP如何实现线程安全

那么PHP的线程安全是如何实现的呢?在这篇文章中,讲解了PHP是如何实现线程安全的。我觉得关键几点有:
1. PHP引入了TSRM,也就是线程安全资源管理器(Thread Safe Resource Manager),这个机制解决线程并发问题。
2. TSRM实现了多线程中函数作用域中的相关变量范围共享,如全局变量、静态全局变量、静态局部变量,除了局部变量。
3. TSRM采用了避免共享状态,包括但不限于,如线程本地存储Thread Local Storage等。这意味着所有线程都可以使用它,但它的值在每一个线程中是单独存储的。
4. 对于那么无法避免共享状态的情况,相关同步的方法采用互斥锁实现。

如何实现线程安全

PHP官方并没有线程相关扩展,PHP 核心开发组的krakjoe自行实现的pthreads的线程扩展库。有几点需要注意:
1. 该扩展只能运行在CLI模型下
2. 要求PHP 7.2+
3. 必须要编译时开启ZTS(Zend Thread Safty),在编译时添加参数 --enable-maintainer-zts可开启ZTS。

好了,我先尝试编译一个ZTS的环境。默认的官方docker镜像是NTS( Non-Thread Safe)的。

PHP 7.2.7 (cli) (built: Dec  3 2018 12:53:48) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.7, Copyright (c) 1999-2018, by Zend Technologies

安装好环境,检查开启ZTS的方式,直接采用“php -v“` 即可。

PHP 7.2.7 (cli) (built: Feb  2 2019 08:51:03) ( ZTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.7, Copyright (c) 1999-2018, by Zend Technologies

通过实现了一个pthreads的实例,放在我的GitHub上,供你参考。

参考链接

  1. Multi-Threading in PHP with pthreads
  2. Easy pthreads Pools
  3. Ubuntu 16.04: How to install ZTS enabled PHP7 and the pThreads module
  4. Parallel Programming with Pthreads in PHP – the Fundamentals
  5. True PHP7 Multi-Threading: How to Rebuild PHP and use pthreads
  6. 什么是线程安全
  7. Wikipedia Thread safety
  8. Thread Safety and Shared Resources
  9. What is this thing you call “thread safe”
  10. 当我们在谈论XX是否线程安全时,我们在谈论什么
  11. 第三节 PHP中的线程安全
  12. Threads and PHP
  13. PHP 进阶之路 – 揭开 PHP 线程安全的神秘面纱
  14. Thread-Safe Resource Manager
  15. 深入研究PHP及Zend Engine的线程安全模型
  16. PHP 高级编程之多线程
  17. How to make a method thread-safe in Java

发表评论

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