首页 > 代码库 > ubuntu系统之难

ubuntu系统之难

要讲解记录锁机制,首先要介绍fcntl函数,如下给出该函数原型:

#include <fcntl.h>

int fcntl(int filedes, int cmd, ... /* struct flock *flockptr */)
函数返回值:若成功则依赖于cmd,若出错则返回-1。

对于记录锁,cmd是F_GETLK, F_SETLOCK, F_SETLKW。第三个参数(称其为flockptr)是一个指向flock结构的指针:

struct flock {
short l_type;    /* F_RDLCK, F_WRLCK, or F_UNLCK */
off_t l_start;    /* offset in bytes, relative to l_whence */
short l_whence;    /* SEEK_SET, SET_CUR, or SEEK_END */
off_t l_len;    /* length, in bytes; 0 means lock to EOF */
pid l_pid;    /* returned with F_GETLK */
};
对flock结构说明如下:

  • 所希望的锁类型:F_RDLCK(共享读锁),F_WRLCK(独占性写锁) 或则 F_UNLCK(解锁一个区域)
  • 要加锁或解锁区域的起始字节偏移,这由l_start和l_whence两者决定。
  • 区域的字节长度,由l_len表示。
  • 具有能阻塞当前进程的锁,其持有进程的ID存放在l_pid中(仅由F_GETLK返回)。
关于加锁和解锁区域的说明还要注意下列各点:

  • l_stat是相对偏移量(字节),l_whence则决定了相对偏移量的起点。这与lseek函数中最后两个参数类似。
  • 该区域可以在当前文件尾端处开始或越过其尾端处开始,但是不能在文件起始位置之前开始。
  • 如若l_len为0,则表示锁的区域从其起点(由l_start和l_whence两者决定)开始直至最大可能偏移量为止,也就是不管添写到该文件中多少数据,它们都在锁的范围内(不必猜测会有多少字节被追加到文件之后)。
  • 为了锁整个文件,我们设置l_start和l_whence,使锁的起点在文件起始处,并且说明长度(l_len)为0
以下说明fcntl函数的三种命令:

F_GETLK:判断由flockptr锁描述的锁是否会被另外一把锁所排斥(阻塞)。如果存在一把锁,它阻止创建由flockptr所描述的锁,则把该现存锁的信息写到flockptr指向的结构中如果不存在这种情况,则将l_type设置为F_UNLOCK外,flockptr所指向结构的其他信息保持不变。

F_SETLK:设置由flockptr所描述的锁。如果试图建立一把读锁(l_type设为F_RDLCK)或写锁(l_type设为F_WRLCK),而按兼容性规则不能允许的情况,fcntl立即出错返回,此时errno设置为EACCES或EAGAIN。此命令也用来清除由flockptr说明的锁(l_type为F_UNLCK)。

F_SETLKW:这是F_SETLK的阻塞版本。如果因为当前在请求区间的某个部分另一个进程已经有一把锁,因而按兼容性规则由flockptr所请求的锁不能被创建,则使调用进程休眠。如果请求创建的锁已经可用,或者休眠由信号中断,则该进程被唤醒。

实际编程中,为了避免每次分配flock结构,然后又填入各项信息,可以用如下函数两处理所有这些细节:

#include <fcntl.h>

int
lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
{
	struct flock	lock;

	lock.l_type = type;		/* F_RDLCK, F_WRLCK, F_UNLCK */
	lock.l_start = offset;	/* byte offset, relative to l_whence */
	lock.l_whence = whence;	/* SEEK_SET, SEEK_CUR, SEEK_END */
	lock.l_len = len;		/* #bytes (0 means to EOF) */

	return(fcntl(fd, cmd, &lock));
}
其他的加读、写或解文件锁的操作就可以定义为如下的宏:

#define	read_lock(fd, offset, whence, len) 			lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define	readw_lock(fd, offset, whence, len) 			lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define	write_lock(fd, offset, whence, len) 			lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define	writew_lock(fd, offset, whence, len) 			lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define	un_lock(fd, offset, whence, len) 			lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))