分享
 
 
 

Apache源代码分析——队列Queue[queue.c]

王朝system·作者佚名  2008-05-18
窄屏简体版  字體: |||超大  

tingya | 18 一月, 2005 22:49

本文分析了Apache中的队列Queue。

/////////////////////////////////////////////////////////////

//Apache源代码分析——配置命令执行过程

//张中庆于西安交通大学软件所

//tingya$stu,xjtu,edu,cn,将$换成@,,换成.防止地址被收集

//转载请保留出处

//最初出自西安交通大学兵马俑Linux版

//////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////

队列通常用来保存

其中最重要的几个数据结构就是fd_queue_info_t,

fd_queue_info_t

struct fd_queue_info_t {

int idlers;

apr_thread_mutex_t *idlers_mutex;

apr_thread_cond_t *wait_for_idler;

int terminated;

int max_idlers;

apr_pool_t **recycled_pools;

int num_recycled;

};

idlers标记当前队列中的空闲消息数目,外部模块根据该值检测是否有可用的消息。如果idlers<=0,则外部调用必须等待,否则从队列中取出消息。

当对队列进行访问的时候必须保证互斥性,这个可以通过队列结构中内嵌的idlers_mutex来保证。

Wait_for_idler用来进行同步处理。如果idlers<=0,队列调用wait_for_idle的Wait使外部模块等待。一旦idlers>=0,其将发送Signal信号唤醒等待的外部调用。

max_idlers表明队列中允许的最大的空闲消息数目。

recycled_pools和num_recycled

///////////////////////////////////////////////////////////////////////////////////////

apr_status_t ap_queue_info_create(fd_queue_info_t **queue_info,

apr_pool_t *pool, int max_idlers)

函数描述:

该函数用来创建消息队列数组queue_info,每个数组元素为fd_queue_info_t类型。创建的消息队列从内存池pool中申请,消息队列最大空闲数目为max_idlers。

流程描述:

函数首先从内存池pool中使用apr_palloc分配一块sizeof(fd_queue_info_t)大小的内存块,对其初始化,将其赋值给内部fd_queue_info_t类型的qi变量。

一旦分配成功,则调用apr_thread_mutex_create对qi中的mutex锁以及同步条件变量进行创建和初始化。继而函数从内存中分配max_idlers个子内存池。最后调用apr_pool_cleanup_register(pool, qi, queue_info_cleanup, apr_pool_cleanup_null)注册内存池的清理函数。

///////////////////////////////////////////////////////////////////////////////////////

apr_status_t ap_queue_info_set_idle(fd_queue_info_t *queue_info,

apr_pool_t *pool_to_recycle)

函数描述:

该函数将内存池pool_to_recyle放入queue_info的备用内存池中。

流程描述:

函数调用之前,首先调用queue_info中的锁进行锁定保证互斥操作。在所有的操作结束后,函数还必须调用该锁进行解锁操作。

一旦函数进行了锁定,如果pool_to_recycle为有效的内存池,函数将将其放入queue_info的recycled_pools数组的末尾,同时空闲内存池数目变量num_recycled加一。

至此,如果当前的idlers数目>=0,表示存在空闲消息队列,此时可以调用signal方法通知等待的调用进程。

///////////////////////////////////////////////////////////////////////////////////////

apr_status_t ap_queue_info_wait_for_idler(fd_queue_info_t *queue_info,

apr_pool_t **recycled_pool)

函数描述:

该函数与ap_queue_info_set_idle是对应的孪生函数。ap_queue_info_set_idle往消息队列中增加空闲内存池,而ap_queue_info_wait_for_idle等待从消息队列中取空闲内存池,如果取不到则等待。取到的空闲内存池在recyled_pool中返回。

流程描述:

当对queue_info中的idler_mutex锁定之后,函数将不断的对两个变量进行判断:idlers和terminiated。如果terminated为1,表示Apache要求其退出等待,此时不再循环,直接退出。如果idlers>=0,系统直接取出空闲内存池。只有当terminated=0并且idlers的时候,函数将调用queue_info内在的wait_for_idle进行等待。即执行下面的代码:

while ((queue_info->idlers == 0) && (!queue_info->terminated)) {

rv = apr_thread_cond_wait(queue_info->wait_for_idler,

queue_info->idlers_mutex);

一旦等待进行被Signal被唤醒,则表明当前存在空闲的内存池使用,此时idlers将立即减一。同时如果空闲内存池的数目num_recycled不为0,则将第num_recyled-1个元素返回出去。

///////////////////////////////////////////////////////////////////////////////////////

此外函数中还定义了几个与消息队列相关的宏:

#define ap_queue_full(queue) ((queue)->nelts == (queue)->bounds)

该宏用来判断fd_queue_t是否已经满了。

#define ap_queue_empty(queue) ((queue)->nelts == 0)

判断给定的fd_queue_t是否为空

上面的两个宏是非线程安全的,因此调用该代码的时候必须放入临界区执行。

///////////////////////////////////////////////////////////////////////////////////////

除了fd_queue_info_t结构之外,关于队列的另外两个重要的数据结构就是fd_queue_t和fd_queue_elem_t。

fd_queue_elem_t描述的使消息队列中放的数据的内容,其定义如下。从中可以看出,每个消息队列包含两个内容,侦听socket描述sd和其该socket所处的内存池。

struct fd_queue_elem_t {

apr_socket_t *sd;

apr_pool_t *p;

};

struct fd_queue_t {

fd_queue_elem_t *data;

int nelts;

int bounds;

apr_thread_mutex_t *one_big_mutex;

apr_thread_cond_t *not_empty;

int terminated;

};

fd_queue_t 是是一个堆栈结构。data中保存实际的堆栈元素,堆栈元素由bounds决定。nelts为用来标记当前的“水位”,即最上面的可用的元素的索引。

one_big_mutex是结构中内嵌的锁,当多线程访问内部数据,比如data,nelts等的时候确保互斥。not_empty是条件变量,用于同步对队列的访问。当队列为空的时候调用not_empty阻塞,否则调用signal唤醒阻塞。

与queue对应的函数包括下面的几个:

apr_status_t ap_queue_init(fd_queue_t *queue, int queue_capacity, apr_pool_t *a);

apr_status_t ap_queue_push(fd_queue_t *queue, apr_socket_t *sd, apr_pool_t *p);

apr_status_t ap_queue_pop(fd_queue_t *queue, apr_socket_t **sd, apr_pool_t **p);

apr_status_t ap_queue_interrupt_all(fd_queue_t *queue);

apr_status_t ap_queue_term(fd_queue_t *queue);

///////////////////////////////////////////////////////////////////////////////////////

apr_status_t ap_queue_init(fd_queue_t *queue, int queue_capacity, apr_pool_t *a);

函数描述:

该函数实际上队列的入口函数,其用来创建一个队列,创建队列所需要的内存从内存池a中申请。

Queue返回创建后的队列指针,queue_capacity是队列的容量,即能够容纳的元素的最大个数。

流程描述:

函数初始化的第一件事情就是创建queue中内嵌的one_big_mutex和条件变量not_empty。一旦创建成功,函数将从内存池a中分配queue_capacity*sizeof(ap_elem_t)的空间,用来“装入”queue_capacity个元素。空间指针由queue->data进行保存。同时queue->bounds赋值为capacity,nelts置为0。同时将queue_capacity个元素中的套接字置为NULL,表示尚未使用。

最后在pool中登记queue销毁时候需要调用的处理函数。当pool中对queue进行销毁的时候将调用ap_queue_destroy函数进行处理。

///////////////////////////////////////////////////////////////////////////////////////

apr_status_t ap_queue_push(fd_queue_t *queue, apr_socket_t *sd, apr_pool_t *p)

函数描述:

该函数将sd“压入”队列queue中。Queue一个先进后出的堆栈一样。

流程描述:

函数在压入之前,将内部代码通过对one_big_mutex进行锁定设置成为临界区,既而函数必须确保当前的空间没有被全部占用,尚有空闲,其次要确保外部没有要求退出。一旦这两项都满足之后,那么函数将元素压入最上面的位置,即netls,同时nelts上移一格,指向新的空闲位置,代码如下:

fd_queue_elem_t *elem;

elem = &queue->data[queue->nelts];

elem->sd = sd;

elem->p = p;

queue->nelts++;

一旦压入新的元素,函数将发出广播通知所有的等待的调用者可以获取新放入的元素。

///////////////////////////////////////////////////////////////////////////////////////

apr_status_t ap_queue_pop(fd_queue_t *queue, apr_socket_t **sd, apr_pool_t **p)

函数描述:

该函数从队列queue中弹出一个元素,取得其中的相关元素。

流程描述:

函数在操作之前将内部代码通过对one_big_mutex进行锁定设置成为临界区。如果队列中没有可用消息,则等待,否则直接取出第nelts-1个元素,同时将“水位”减一。

elem = &queue->data[--queue->nelts];

*sd = elem->sd;

*p = elem->p;

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有