APR分析-进程同步篇

APR分析-进程同步篇

最新的统计数据显示Apache服务器在全世界仍然占据着Web服务器龙头老大的位置,而且市场占有率遥遥领先,所以学习Apache相关知识是完全正确的方向,这里我们继续分析APR进程同步相关内容。

进程同步的源代码的位置在$(APR_HOME)/locks目录下,本篇blog着重分析unix子目录下的proc_mutex.c、global_mutex文件内容,其相应头文件为$(APR_HOME)/include/apr_proc_mutex.h、apr_global_mutex.h。其用于不同进程之间的同步以及多进程多线程中的同步问题。

APR提供三种同步措施,分别为:

apr_thread_mutex_t -支持单个进程内的多线程同步;

apr_proc_mutex_t -支持多个进程间的同步;

apr_global_mutex_t  -支持不同进程内的不同线程间同步。

在本篇中着重分析apr_proc_mutex_t。

1、同步机制

APR提供多种进程同步的机制供选择使用。在apr_proc_mutex.h中列举了究竟有哪些同步机制:

typedef enum {

APR_LOCK_FCNTL,         /*记录上锁*/

APR_LOCK_FLOCK,         /*文件上锁*/

APR_LOCK_SYSVSEM,       /*系统V信号量*/

APR_LOCK_PROC_PTHREAD,  /*利用pthread线程锁特性*/

APR_LOCK_POSIXSEM,      /* POSIX信号量*/

APR_LOCK_DEFAULT        /*默认进程间锁*/

} apr_lockmech_e;

这几种锁机制,随便拿出哪一种都很复杂。APR的代码注释中强调了一点就是“只有APR_LOCK_DEFAULT”是可移植的。这样一来用户若要使用APR进程同步机制接口,就必须显式指定一种同步机制。

2、实现点滴

APR提供每种同步机制的实现,每种机制体现为一组函数接口,这些接口被封装在一个结构体类型中:

/* in apr_arch_proc_mutex.h */

struct apr_proc_mutex_unix_lock_methods_t {

unsigned int flags;

apr_status_t (*create)(apr_proc_mutex_t *,const char *);

apr_status_t (*acquire)(apr_proc_mutex_t *);

apr_status_t (*tryacquire)(apr_proc_mutex_t *);

apr_status_t (*release)(apr_proc_mutex_t *);

apr_status_t (*cleanup)(void *);

apr_status_t (*child_init)(apr_proc_mutex_t **,apr_pool_t *, const char *);

const char *name;

};

之后在apr_proc_mutex_t类型中,apr_proc_mutex_unix_lock_methods_t的出现也就在情理之中了:)

/* in apr_arch_proc_mutex.h */

struct apr_proc_mutex_t {

apr_pool_t *pool;

const apr_proc_mutex_unix_lock_methods_t *meth;

const apr_proc_mutex_unix_lock_methods_t*inter_meth;

int curr_locked;

char *fname;

... ...

#if APR_HAS_PROC_PTHREAD_SERIALIZE

pthread_mutex_t *pthread_interproc;

#endif

};

这样APR提供的用户接口其实就是对mech各个“成员函数”功能的“薄封装”,而真正干活的其实是apr_proc_mutex_t中的meth字段的“成员函数”,它们的工作包括mutex的创建、获取(加锁)和清除(解锁)等。以“获取锁”为例APR的实现如下:

APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t*mutex)

{

return mutex->meth->acquire(mutex);

}

3、同步机制

按照枚举类型apr_lockmech_e的声明,我们知道APR为我们提供了5种同步机制,下面分别简单说说:

(1)记录锁

记录锁是一种建议性锁,它不能防止一个进程写已由另一个进程上了读锁的文件,它主要利用fcntl系统调用来完成锁功能的,记得在以前的一篇关于APR文件I/O的Blog中谈过记录锁,这里不再详细叙述了。

(2)文件锁

文件锁是记录锁的一个特例,其功能由函数接口flock支持。值得说明的是它仅仅提供“写入锁”(独占锁),而不提供“读入锁”(共享锁)。

(3) System V信号量

System V信号量是一种内核维护的信号量,所以我们只需调用semget获取一个System

V信号量的描述符即可。值得注意的是与POSIX的单个“计数信号量”不同的是System

V信号量是一个“计数信号量集”。所以我们在注意的是在初始化时设定好信号量集的属性以及在调用semop时正确选择信号量集中的信号量。在APR的System

V信号量集中只是申请了一个信号量。

(4)利用线程互斥锁机制

APR使用pthread提供的互斥锁机制。原本pthread互斥锁是用来互斥一个进程内的各个线程的,但APR在共享内存中创建了pthread_mutex_t,这样使得不同进程的主线程实现互斥,从而达到进程间互斥的目的。截取部分代码如下:

new_mutex->pthread_interproc = (pthread_mutex_t *)mmap(

(caddr_t) 0,

sizeof(pthread_mutex_t),

PROT_READ | PROT_WRITE, MAP_SHARED,

fd, 0);

(5) POSIX信号量

APR使用了POSIX有名信号量机制,从下面的代码中我们可以看出这一点:

/* in proc_mutex.c */

apr_snprintf(semname, sizeof(semname),"/ApR.%lxZ%lx", sec, usec); /* APR自定义了一种POSIX信号量命名规则,在源代码中有说明*/

psem = sem_open(semname, O_CREAT, 0644, 1);

4、如何使用

我们知道父进程的锁其子进程并不继承。APR进程同步机制的一个典型使用方法就是:“Createthe

mutex in the Parent,Attach to it in the Child”。APR提供接口apr_proc_mutex_child_init在子进程中re-open

themutex。

5、小结

APR提供多种锁机制,所以使用的时候要根据具体应用情况细心选择。

你可能感兴趣的:(APR分析-进程同步篇)