低级文件编程库常常用于方位终端、管道、设备和套接字等特殊文件,一般不用于普通磁盘文件,这是标准文件编程库的特长。
低级文件编程库听起来似乎很低级,其实它是UNIX中的I/O系统调用。它使用文件描述符,直接读写各类文件。低级文件编程库在输入输出上只有块读写的功能。
文件锁
多用户多任务操作系统非常重要的一个内容就是文件锁。用户在更新文件时,期望可以使用某种机制,防止两个进程同时更新文件同一区域的内容巍峨造成写丢失,或者防止文件内容在未更新完毕时被读取等并发引起的问题,这种机制就是文件锁。
进程在操作文件期间,可以使用文件所,锁定文件中的敏感信息,防止其它的进程操作该部分信息。函数fcntl提供了对文件任意区域设置锁的能力,既可以锁住全部文件,又可以锁住文件的部分记录,股文件锁由称为“记录锁”。
根据文件锁的访问方式,可以区分为读锁和写锁两种。文件记录在同一时刻,可以设置多个读锁,但仅仅能设置一个写锁,并且读写锁不能同时存在。
当函数fcntl专用于锁操作时,其原型为:
int fcntl(int fileds, int cmd, struct flock *arg);
其中,结构flock用于描述文件锁的信息,定义在头文件"fcntl.h"中,如下所示:
strct flock
{
short l_type; //锁类型,取值为F_RDLCk, F_WRLCK 或者 F_UNLCK 之一
short l_whence; //锁区域开始地址的相对位置,取值为SEEK_SET, SEEK_CUR 或者 SEEK_END 之一
off_t l_start; //锁区域的开始地址偏移量
off_t l_len; //锁区域的长度, 0 表示锁至文件末
off_t l_pid; //拥有锁的进程ID号
};
函数fcntl在专用于锁操作时,参数cmd有三种取值:
(a) F_GETLK. 获取文件描述符fileds对应文件制定区域的文件锁信息。
(b) F_SETLK. 在文件描述符fileds 对应的文件的制定区域设置锁信息。
(C) F-SETLKW. 该命令是F_SETLK命令的阻塞版本。
文件锁最典型应用于两方面:一是锁定文件中的临界数据,比如并发投票时文件记录的投票数; 二是利用具有互斥性质的写锁,实现进程的并发控制。
在锁机制的使用中,最常见的操作有锁的请求、释放、测试等;
(a) 测试锁。设计函数SeeLock,查询文件描述符fd对应文件的锁信息。
void SeeLock(int fd, int start, int len)
{
struct flock arg;
arg.l_type = F_WRLCK;
arg.l_whence = SEEK_SET;
arg.l_start = start;
arg.l_len = len;
if(fcntl(fd, F_GETLK, &arg) == -1)
{
fprintf(stderr, "See Lock failed./n");
}
else if(arg.l_type == F_UNLCK)
{
fprintf(stderr, "No Lock From %d to %d /n", start, start+len);
}
else if(arg.l_type == F_WRLCK)
{
fprintf(stderr, "Write Lock From %d to %d, id = %d/n", start, start+len, arg.l_pid);
}
else if(arg.l_type == F_WRLCK)
{
fprintf(stderr, "Read Lock From %d to %d, id = %d/n", start, start+len, arg.l_pid);
}
}
(b) 申请读锁。 以阻塞方式设计共享读锁申请函数GetReadLock。
void GetReadLock(int fd, int start, int len)
{ // 以阻塞方式在描述符fd对应文件中从start处的len字节上申请共享读锁
struct flock arg;
arg.l_type = F_RDLCK;
arg.l_whence = SEEK_SET;
arg.l_start = start;
arg.l_len = len;
if(fcntl(fd, F_SETLKW, &arg) == -1)
fprintf(stderr, "[%d] See Read Lock failed./n", getpid());
else
fprintf(stderr, "[%d] Set Read Lock From %d to %d/n", getpid(), start, start+len);
}
(c) 申请写锁. 以阻塞方式设计互斥写锁申请函数GetWrtieLock.
void GetWriteLock(int fd, int start, int len)
{ // 以阻塞方式在描述符fd对应文件中从start处的len字节上申请互斥写锁
struct flock arg;
arg.l_type = F_WRLCK;
arg.l_whence = SEEK_SET;
arg.l_start = start;
arg.l_len = len;
if(fcntl(fd, F_SETLKW, &arg) == -1)
fprintf(stderr, "[%d] See Write Lock failed./n", getpid());
else
fprintf(stderr, "[%d] Set Write Lock From %d to %d/n", getpid(), start, start+len);
}
(d) 释放锁. 设计文件锁释放函数ReleaseLock.
void ReleaseLock(int fd, int start, int len)
{ // 在描述符fd对应文件中释放从start处的len字节上的锁
struct flock arg;
arg.l_type = F_UNLCK;
arg.l_whence = SEEK_SET;
arg.l_start = start;
arg.l_len = len;
if(fcntl(fd, F_SETLKW, &arg) == -1)
fprintf(stderr, "[%d] UnLock failed./n", getpid());
else
fprintf(stderr, "[%d] UnLock From %d to %d/n", getpid(), start, start+len);
}