php线程安全的问题

php 多线程有什么问题?

线程的并发问题。

在多线程系统中,进程保留着资源所有权的属性,而多个并发执行流是执行在进程中运行的线程。如Apache2 中的woker,主控制进程生成多个子进程,每个子进程中包含固定的线程数,各个线程独立地处理请求。同样,为了不在请求到来时再生成线程,MinSpareThreads和MaxSpareThreads设置了最少和最多的空闲线程数;而MaxClients设置了所有子进程中的线程总数。如果现有子进程中的线程总数不能满足负载,控制进程将派生新的子进程。

当PHP运行在如上类似的多线程服务器时,此时的PHP处在多线程的生命周期中。在一定的时间内,一个进程空间中会存在多个线程,同一进程中的多个线程公用模块初始化后的全局变量,如果和PHP在CLI模式下一样运行脚本,则多个线程会试图读写一些存储在进程内存空间的公共资源(如在多个线程公用的模块初始化后的函数外会存在较多的全局变量),

 

此时这些线程访问的内存地址空间相同,当一个线程修改时,会影响其它线程,这种共享会提高一些操作的速度,但是多个线程间就产生了较大的耦合,并且当多个线程并发时,就会产生常见的数据一致性问题或资源竞争等并发常见问题,比如多次运行结果和单线程运行的结果不一样。

 

 

 

 

 

php 线程安全版本 如何实现的?

PHP引入了TSRM: 线程安全资源管理器(Thread Safe Resource Manager)。

TRSM 的实现代码在 PHP 源码的 /TSRM 目录下,调用随处可见,通常,我们称之为 TSRM 层。一般来说,TSRM 层只会在被指明需要的时候才会在编译时启用(比如,Apache2+worker MPM,一个基于线程的MPM),因为Win32下的Apache来说,是基于多线程的,所以这个层在Win32下总是被开启的。

 

进程保留着资源所有权的属性,线程做并发访问,PHP中引入的TSRM层关注的是对共享资源的访问,这里的共享资源是线程之间共享的存在于进程的内存空间的全局变量。当PHP在单进程模式下时,一个变量被声明在任何函数之外时,就成为一个全局变量。

PHP解决并发的思路非常简单,既然存在资源竞争,那么直接规避掉此问题,将多个资源直接复制多份,多个线程竞争的全局变量在进程空间中各自都有一份,各做各的,完全隔离。以标准的数组扩展为例,首先会声明当前扩展的全局变量,然后在模块初始化时会调用全局变量初始化宏初始化array的,比如分配内存空间操作。

这里的声明和初始化操作都是区分ZTS和非ZTS,对于非ZTS的情况,直接就是声明变量,初始化变量。对于ZTS情况,PHP内核会添加TSRM,对应到这里的代码就是声明时不再是声明全局变量,而是用ts_rsrc_id代码,初始化是不再是初始化变量,而是调用ts_allocate_id函数在多线程环境中给当前这个模块申请一个全局变量并返回资源ID。

资源ID变量名由模块名和global_id组成。它是一个自增的整数,整个进程会共享这个变量,在进程SAPI初始调用,初始化TSRM环境时, id_count作为一个静态变量将被初始化为0。这是一个非常简单的实现,自增。确保了资源不会冲突,每个线程的独立。

 

参考文档:

http://www.laruence.com/2008/08/03/201.html

https://www.cnblogs.com/zhenbianshu/p/7978835.html

posted @ 2018-04-08 11:39  小'帅  阅读(248)  评论(0编辑  收藏  举报