【PHP内核学习】线程安全

来源:互联网 发布:毒品是谁发明的知乎 编辑:程序博客网 时间:2024/06/05 05:37

PHP同一进程下的多个线程会试图读写一些存储在进程内存空间的公共资源,此时这些线程访问的内存地址空间相同,当一个线程修改时,会影响其它线程,这种共享会提高一些

操作的速度, 但是多个线程间就产生了较大的耦合,并且当多个线程并发时,就会产生常见的数据一致性问题或资源竞争等并发常见问题。


如果每个线程中对全局变量、静态变量只有读操作,而无写操作,则这些个全局变量就是线程安全的.

为解决线程的并发问题,PHP引入了TSRM: 线程安全资源管理器(Thread Safe Resource Manager)。 TRSM 的实现代码在 PHP 源码的 /TSRM 目录下,我们称之为 TSRM 层。

我的php源码位置(gentoo  x86_64 GNU/Linux):



PHP的线程安全策略是将线程的共享资源复制多份,进程中的每个线程各自都有一份共享资源的拷贝,各做各的,完全隔离

原理图:


(图片出处:http://blog.codinglabs.org/uploads/pictures/zend-thread-safety/1.png)


_tsrm_tls_entry(TSRM )结构体:

struct _tsrm_tls_entry {    void **storage;    int count;    THREAD_T thread_id;    tsrm_tls_entry *next;};

每个tsrm_tls_entry结构负责表示一个线程的所有全局变量资源,其中thread_id存储线程ID,count记录全局变量数,next指向下一个节点。storage可以看做指针数组,其中每个元素是一个指向本节点代表线程的一个全局变量。最终各个线程的tsrm_tls_entry被组成一个链表结构,并将链表头指针赋值给一个全局静态变量tsrm_tls_table。注意,因为tsrm_tls_table是一个货真价实的全局变量,所以所有线程会共享这个变量,这就实现了线程间的内存管理一致性。


(图片出处:http://blog.codinglabs.org/articles/zend-thread-safety.html)


通过一个ts_allocate_id()函数为新的线程分配一个线程安全资源id(thread safe resource id):

/* allocates a new thread-safe-resource id */TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor){    int i;    TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtaining a new resource id, %d bytes", size));    tsrm_mutex_lock(tsmm_mutex);//互斥锁    /* obtain a resource id */    *rsrc_id = TSRM_SHUFFLE_RSRC_ID(id_count++); //id_count即为当前进程下的线程数量    TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Obtained resource id %d", *rsrc_id));    /* store the new resource type in the resource sizes table */    if (resource_types_table_size < id_count) {        resource_types_table = (tsrm_resource_type *) realloc(resource_types_table, sizeof(tsrm_resource_type)*id_count);//重新分配内存        if (!resource_types_table) {            tsrm_mutex_unlock(tsmm_mutex);            TSRM_ERROR((TSRM_ERROR_LEVEL_ERROR, "Unable to allocate storage for resource"));            *rsrc_id = 0;            return 0;        }        resource_types_table_size = id_count;    }    resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].size = size;    resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].ctor = ctor;    resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].dtor = dtor;    resource_types_table[TSRM_UNSHUFFLE_RSRC_ID(*rsrc_id)].done = 0;    /* enlarge the arrays for the already active threads */    for (i=0; i<tsrm_tls_table_size; i++) {        tsrm_tls_entry *p = tsrm_tls_table[i];        while (p) {            if (p->count < id_count) {                int j;                p->storage = (void *) realloc(p->storage, sizeof(void *)*id_count);                for (j=p->count; j<id_count; j++) {                    p->storage[j] = (void *) malloc(resource_types_table[j].size);                    if (resource_types_table[j].ctor) {                        resource_types_table[j].ctor(p->storage[j], &p->storage);                    }                }                p->count = id_count;            }            p = p->next;        }    }    tsrm_mutex_unlock(tsmm_mutex);    TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Successfully allocated new resource id %d", *rsrc_id));    return *rsrc_id;}


---------------------

珠玉在前:

1.http://blog.codinglabs.org/articles/zend-thread-safety.html

2.http://blog.csdn.net/hackooo/article/details/8856225

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

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 宝宝脖子有点偏左边歪怎么办 宝宝脖子偏了怎么办呢 斜颈导致的脸歪怎么办 斜颈手术后脸部还不对称怎么办 宝宝3个月斜颈怎么办 一岁八个月宝宝斜颈怎么办 四个月宝宝有点斜颈怎么办 一岁宝宝有点偏怎么办 6个月宝宝有点斜颈怎么办 四个月宝宝左侧胸锁乳突肌厚怎么办 脖子疼好几天了怎么办 有双下巴怎么办才能瘦掉 胃突然疼的厉害怎么办 手劳损痛的厉害怎么办 手臂扭到了很疼怎么办 寒湿导致肩膀痛怎么办 吃辣脖子肿了怎么办 脖子长了个肿瘤怎么办 一边背高一边低怎么办 生完孩子肩宽了怎么办 狗狗脖子上长囊肿怎么办 胸肋关节韧带疼怎么办 三岁宝宝有点驼背怎么办 20多岁有点驼背怎么办 五岁宝宝有点驼背怎么办 孕妇腰扭了很痛怎么办 怀孕了腰扭了疼怎么办 小龙芭比扭腰机开机没有声音怎么办 高中生训练数学计算的准确性怎么办 跑步累了跑不动了怎么办 一跑步就岔气了怎么办 婴儿关节折邹发红怎么办? 打了借条人跑了怎么办 吃凉的胃不舒服怎么办 跑步机带子跑偏怎么办 在跑步机上摔倒怎么办 弯道以后就是直线行驶怎么办 跑步机的声音大怎么办 科二一直考不过怎么办 考科目三太紧张怎么办 科目三太紧张了怎么办