Swoole源码学习记录(四)——锁和信号(一)

Swoole版本:1.7.4-stable

写在开头的废话:原本计划是于第四章开始reactor模块的分析,但是发现reactor模块牵扯到太多的其他模块,没法一开始就直接分析reactor,只能将其延后。一番考察之后,我决定从swoole的Lock模块入手继续分析。这一块我的知识储备有很大的空缺,估计会比较吃力……

 

--------------------------------------------我是分割线 -----------------------------------------------

 

Swoole中关于Lock模块的全部声明在swoole.h文件的 364 – 461行(结构体声明)以及534 – 551 行(函数声明),包括swFileLock(文件锁),swMutex(互斥锁),swRWLock(读写锁),swSpinLock(自旋锁),swAtomicLock(原子锁),swSem(信号量)和swCond(条件变量)。其中除了swCond以外,其他锁和信号都通过swLock做了进一步封装。

 

Swoole声明了一个枚举类型SW_LOCKS用来代表这些不同类型的锁,其定义如下:

enum SW_LOCKS
{
         SW_RWLOCK = 1,
#define SW_RWLOCK SW_RWLOCK
         SW_FILELOCK = 2,
#define SW_FILELOCK SW_FILELOCK
         SW_MUTEX = 3,
#define SW_MUTEX SW_MUTEX
         SW_SEM = 4,
#define SW_SEM SW_SEM
         SW_SPINLOCK = 5,
#define SW_SPINLOCK SW_SPINLOCK
         SW_ATOMLOCK = 6,
#define SW_ATOMLOCK SW_ATOMLOCK
};

首先是swLock结构体,该结构体是全部锁类型的总封装,其定义在swoole.h文件的429 – 449行,声明如下:

struct _swLock
{
         int type;                      // 锁的类型,取值于SW_LOCKS
         union                           //锁的对象,一个union,稍后分析
         {
                   swMutex mutex;
                   swRWLock rwlock;
                   swFileLock filelock;
                   swSem sem;
                   swAtomicLock atomlock;
#ifdefHAVE_SPINLOCK
                   swSpinLock spinlock;
#endif
         } object;
         int (*lock_rd)(struct _swLock *lock);                // 以下是六个操作函数
         int (*lock)(struct _swLock *lock);
         int (*unlock)(struct _swLock *lock);
         int (*trylock_rd)(struct _swLock*lock);
         int (*trylock)(struct _swLock *lock);
         int (*free)(struct _swLock *lock);
};

这里的union(中译“联合体”)是一个非常好的设计,这保证了在同一时刻,一个swLock只会存在一个类型的锁。这里需要做一下特别说明,lock_rd和trylock_rd两个函数是专门为了swFileLock和swRWLock设计的,其他锁没有这两个函数。

那么,一个个来。首先是文件锁,文件锁的结构体声明在swoole.h的 385 – 389 行:

//文件锁
typedef struct _swFileLock
{
         struct flock lock_t;
         int fd;
}swFileLock;

其中struct flock lock_t为Linux系统的文件锁结构,intfd为被锁控制的文件描述符。(struct flock的详细说明参考http://www.gnu.org/software/libc/manual/html_node/File-Locks.html

 

创建一个文件锁的函数声明在swoole.h的537行,如下:

int swFileLock_create(swLock *lock, int fd);

其定义就是初始化一个type为SW_FILELOCK的锁并指定其对应的操作函数。

文件锁的操作函数声明在FileLock.c文件中,其声明如下:

static int swFileLock_lock_rd(swLock *lock);
static int swFileLock_lock_rw(swLock *lock);
static int swFileLock_unlock(swLock *lock);
static int swFileLock_trylock_rw(swLock *lock);
static int swFileLock_trylock_rd(swLock *lock);
static int swFileLock_free(swLock *lock);

其中rd代表读锁,rw代表写锁。

这里需要介绍一下fcntl函数,其函数原型为:

int fcntl(int fd, int cmd); 
int fcntl(int fd, int cmd, long arg); 
int fcntl(int fd, int cmd, struct flock *lock);

在这里,该函数仅用于申请和释放文件锁,因此只用到了两个cmd:F_SETLK 和F_SETLKW。

F_SETLK:在指定的字节范围获取锁(F_RDLCK, F_WRLCK)或释放锁(F_UNLCK)。如果和另一个进程的锁操作发生冲突,返回 -1并将errno设置为EACCES或EAGAIN。

F_SETLKW:行为如同F_SETLK,除了不能获取锁时会睡眠等待外。如果在等待的过程中接收到信号,会即时返回并将errno置为EINTR。

回到swFileLock。因为每个函数很短,所以这里直接贴出全部操作函数:

// 申请文件读锁RDLOCK,不能获得锁时睡眠等待
static int swFileLock_lock_rd(swLock *lock)
{
         lock->object.filelock.lock_t.l_type= F_RDLCK;
         return fcntl(lock->object.filelock.fd, F_SETLKW, &lock->object.filelock);
}
// 申请文件写锁,不能获得锁时睡眠等待
static int swFileLock_lock_rw(swLock *lock)
{
         lock->object.filelock.lock_t.l_type= F_WRLCK;
         return fcntl(lock->object.filelock.fd, F_SETLKW, &lock->object.filelock);
}
// 释放文件锁
static int swFileLock_unlock(swLock *lock)
{
         lock->object.filelock.lock_t.l_type= F_UNLCK;
         return fcntl(lock->object.filelock.fd, F_SETLKW, &lock->object.filelock);
}
// 尝试是否能申请写锁,如果不能获得锁,返回-1
static int swFileLock_trylock_rw(swLock *lock)
{
         // lock->object.filelock.lock_t.l_type= F_RDLCK;    // 该处为原代码,经作者确认为bug,下一行是正确的代码
         lock->object.filelock.lock_t.l_type = F_WRLCK;
         return fcntl(lock->object.filelock.fd, F_SETLK, &lock->object.filelock);
}
// 尝试是否能申请读锁,如果不能获得锁,返回-1
static int swFileLock_trylock_rd(swLock *lock)
{
         // lock->object.filelock.lock_t.l_type= F_WRLCK; // 该处为原代码,经作者确认为bug,下一行是正确的代码
         lock->object.filelock.lock_t.l_type =F_RDLCK;
         return fcntl(lock->object.filelock.fd, F_SETLK, &lock->object.filelock);
}
// 调用close函数释放锁
static int swFileLock_free(swLock *lock)
{
         return close(lock->object.filelock.fd);
}

这里可能有的人会有疑问:明明fcntl的函数要求传入一个flock结构体,而这里却传入了一个swFileLock结构体呢?因为这里flock结构体位于swFileLock结构体头部,swFileLock的首地址就是flock结构体的首地址。

(swoole的文件锁本身并没有复杂的结构,这里需要对flock以及fcntl函数有足够的了解,本文仅作简单说明,详细信息请参考http://www.cnblogs.com/papam/archive/2009/09/02/1559154.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值