11# 第三节 PHP中的线程安全
22
3+ 从作用域上来说,C语言可以定义4种不同的变量:全局变量,静态全局变量,局部变量,静态局部变量。
4+ 下面仅从函数作用域的角度分析一下不同的变量,假设所有变量声明不重名。
5+ 全局变量,在函数外声明,例如,` int gVar; ` 。
6+ 全局变量,所有函数共享,在任何地方出现这个变量名都是指这个变量。
7+ 静态全局变量(` static sgVar ` ),其实也是所有函数共享,但是这个会有编译器的限制,算是编译器提供的一种功能。
8+ 局部变量(函数/块内的` int var; ` ),不共享,函数的多次执行中涉及的这个变量都是相互独立的,他们只是重名的不同变量而已。
9+ 局部静态变量(函数中的` static int sVar; ` ),本函数间共享,函数的每一次执行中涉及的这个变量都是这个同一个变量。
10+
11+ 上面几种作用域都是从函数的角度来定义作用域的,可以满足所有我们对单线程编程中变量的共享情况。
12+ 现在我们来分析一下多线程的情况。在多线程中,多个线程共享除函数调用栈之外的其他资源。
13+ 因此上面几种作用域从定义来看就变成了。
14+ 全局变量,所有函数共享,因此所有的线程共享,不同线程中出现的不同变量都是这同一个变量。
15+ 静态全局变量,所有函数共享,也是所有线程共享。
16+ 局部变量,此函数的各次执行中涉及的这个变量没有联系,因此,也是各个线程间也是不共享的。
17+ 静态局部变量,本函数间共享,函数的每次执行涉及的这个变量都是同一个变量,因此,各个线程是共享的。
18+ 于是还缺少一种同一个线程中的所有函数共享,不同线程中的函数不共享的变量。
19+ 就是说,线程1调用函数` fnA,fnB ` 中的同名变量是同一个变量(如上假设任何地方不会声明重名的变量)。
20+ 而线程2调用函数` fnA,fnB ` 的时候,虽然他们是同一个变量,但是与线程1中的那个变量不是同一个变量。
21+ C语言里是不提供这样的变量作用域,因此需要代码中自己实现。
22+
23+ PHP可以运行在单线程和多线程的模式下,因此PHP必然需要实现一个上述的作用域。
24+ PHP作为一个开源项目,必然具有可扩展性。显然写PHP扩展的人不应该也不希望去修改PHP的核心代码。
25+ 也希望尽量少的涉及PHP核心代码的实现以及PHP会运行在单线程还是多线程模式下。
26+ 而TSRM 就是解决上述作用域的问题和程序员的需求的。
27+
28+
329## 缘起TSRM
430在多线程系统中,进程保留着资源所有权的属性,而多个并发执行流是执行在进程中运行的线程。
531如 Apache2 中的 worker,主控制进程生成多个子进程,每个子进程中包含固定的线程数,各个线程独立地处理请求。
@@ -25,9 +51,11 @@ TRSM 的实现代码在 PHP 源码的 /TSRM 目录下,调用随处可见,通
2551这里的共享资源是线程之间共享的存在于进程的内存空间的全局变量。
2652当 PHP 在单进程模式下时,一个变量被声明在任何函数之外时,就成为一个全局变量。
2753
54+ <!--
2855PHP 解决并发的思路非常简单,既然存在资源竞争,那么直接规避掉此问题,
2956将多个资源直接复制多份,多个线程竞争的全局变量在进程空间中各自都有一份,各做各的,完全隔离。
3057这句话说的非常抽象,到底 TSRM 是如何实现的呢,下面配合代码和绘图逐步说明。
58+ -->
3159
3260首先定义了如下几个非常重要的全局变量(这里的全局变量是多线程共享的)。
3361
0 commit comments