Chinaunix首页 | 论坛 | 博客
  • 博客访问: 160492
  • 博文数量: 83
  • 博客积分: 3956
  • 博客等级: 中校
  • 技术积分: 663
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-24 16:29
文章分类

全部博文(83)

文章存档

2010年(83)

我的朋友

分类: C/C++

2010-10-18 10:06:16

    当人同时一个文件时,其后果将呢?在很多中,该文件最后状态取决于写该文件的最后一个进程。但是对于有些,例如数据库,有时进程需要确保它正在单独写一个文件。为了向进程提供这种能力,较新的Unix系统提 供了记录锁机制。(在第十六章中包含了使用记录锁的数据库子程序库。)

  记录锁机制的是:一个进程正在读或的某个部分时,可以阻止其它进程修改同一文件区。对于Unix,记录这个定语也是误用,因为Unix系 统核根本没有使用文件记录这种概念。一个更适合的术语可能是区域锁,因为它的只是文件的一个区域(也可能是整个文件)。

  在本节的最后部分将说明建议性锁和强制性锁之间的区别。POSIX.1了以fcnt l函数为基础的系统V的记录锁。这种风格也得到4.3BSD Reno版本的支持。早期的贝克莱版只支持BSD flock函数。此函数只锁整个文件,而不锁文件中的一个区域。但是POSIX.1的fcntl函数可以锁文件中的任一区域,大至整个文件,小至单个字 节。

  在本书中只说明POSIX.1的fcntl锁。系统V的lockf函数只是fcntl函数的一个。记录锁是1980年由John Bass最早加到Version7上的。系统核中相应系统入口项是名为locking的函数。此函数提供了强制性记录锁能,它传到了很多制造商的系统III版本。Xenix系统采用了此函数,SVR4在Xenix兼容库中仍旧支 持该函数。

  SVR2是系统V中第一个支持fcntl风格记录锁的版本(1984)。

  fcntl记录锁

  fcntl函数的原型

#include
#include
#include
int fcnt1(int filedes,int ,…/* flock *flockptr */);

  返回:若成功依赖于cmd(见下)错为-1

  对于记录锁,cmd是F_GETLK、F_SETLK或F_SETLKW。第三个(我们将其称为flockptr)是一个指向flock结构的。

Struct flock{
short l_; /* F_RDLCK,F_WRLCK, 或 F_UNLCK */
off_t l_; /*相对于l_whence的字节位移量*/
short l_whence /_SET,SEEK_CUR,或SEEK_END */
off_t l_len; /*长度(字节),O表示锁至EOF */
pid_t l_pid; /*随F--FETLK命令返回
}

flock结构说明:

  所希望的锁类型:F_RDLCK(读锁)、F_WRLCK(独占性写锁)、或F_UNLCK(解锁一个区域)

  要加锁或解锁的区域的起始,它由l_stant和l_whence两者决定。l_stat是相对位移量(字节),l_whence 则决定了相对位移量的起。这与lseek中的使用方法一样。区域的长度,这由l_len表示。加锁和解锁区域的说明还要注意下列各点:

  该区域可以在当前文件尾端处开始或超过其尾端处开始,但是不能在文件起始位置之前开始或越过该起始位置。

  如若l_len为0,则表示锁的区域从其起点(由l_start和l_whence决定)开始直至最大可能位置为止。也就是不管添写到该文件中多少数据,它都处于锁的范围。

  为了锁整个文件,通常的方法是将l_start说明为0,l_whence说明为SEEK_SET,l_len说明为0。

  上面提到了两个锁类型:共享读锁(l_type为F_RDLCK)和独占写琐(F_WRLCK)。基本规则是:多个进程在一个给定的字节上可以有一把 共享的读锁,但是在一个给定字节上的写锁则只能由一个进程独用。更进一步而言,如果在一个给定加字节上已经有一把或多把读锁,则不能在该字节上再加写锁; 如果在一个字节上已经有一把独占性的写锁,则不能再对它加任何读锁。在图12.2中示出了这些规则。

  为了加读锁,该描述必须是读打开,为了加写锁,该描述符是写打开。

  现在说明fcntl函数的三种命令。

  F_GETLK 决定由flockptr所说明的锁是否被另外一把锁所排斥(阻塞)。如果存在一把锁,它阻止由flockptr所描述符的锁,则这把现存的锁的信息写到flockptr指向的结构中;如果不存在这种 情况,则除l_type设置为F_UNLCK之外,flockptr所指向结构中的其它信息、保持不变。

  F_SETLK 设置由flockptr所描述的锁。如果试图建立一把按上述兼容性规则并不允许的锁,则fcntl立即返回,此时errno设置为EACCES或EAGAIN。SVR2和SVR4返回EACCES,但手册页警 告将来返回EAGAIN。4.3+BSD则返回EAGAIN。POSIX.1允许这两种情况。此命令也用来清除由flockptr说明的锁(l_type 为F_UNLCK)。

  F_SETLKW 这是F_SETLK的阻塞版本(命令名中的W表示等待(wait))。如果由于存在其它锁,那么按兼容性规则由flockptr所要求的锁不能被创建,则 调用进程睡眠。如果到则睡眠中断。

  应当,用F_GETLK能否建立一把锁,然后用F_SETLK和F_SETLKW企图建立一把锁,这两者不是一个原子作。在这两个操作之间可能会有另一个进程并建立一把相关的锁,使原来测试到的情况发生变化,如果不希望在建立锁时可能产生的长期阻塞,则应使用 F_SETLK,并对返回结果进行测试,以判别是否成功地建立了所要求的锁。

  在设置或释放在一个文件上的一把锁时。系统按需组合或裂开相邻区。例如若100-199字节是加锁 的区,然后解锁第150字节,则系统核将维持两把锁,一把是从100-149字节,另一把是从151-199字节。

实例-要释放一把锁

  为了免于每次分配flock结构,然后又填入各项信息,可以用程序12.2中的函数_reg来处理这些细节。

#include
#include
#include ourhdr.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
     lock.l_whence = whence; /* SEEK_SET, SEEK_CUR,   SEEK_END */
     lock.l_len = len; /* #bytes (0 means to EOF) */
     l_whence */ ( fcntl(fd, cmd, lock) );
}

  程序 锁和解锁一个文件区域的函数

  因为大多数锁调用是锁或解锁一个文件区域(命令F_GETLK很少使用)。我们通常使用下列五个,它们都在ourhdr.h中(附录B)。

#define _lock(fd,offset,whence,len)
lock_reg(fd,F_SETLK,F_RDLCK,offset,whence,len)
#define needw_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)

  我们以lseek函数中的同样顺序定义了这些宏中的三个参数。

实例-测试一把锁

  程序12.3定义了一个函数lock_,可用其测试一把锁。

#include
#include
#include ourhdr.h

pid_t
lock_test(int fd, int type, off_t offset, int whence, off_t len)
{
   struct flock lock;
   lock.l_type = type; /* F_RDLCK or F_WRLCK */
   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) */
   if (fcntl(fd, F_GETLK, lock) 0)
   err_sys(fcntl );
   if (lock.l_type == F_UNLCK)
   return(0); /* false, region locked by   anotheproc */
   return(lock.l_pid); /* , return pid of lock owner */
}

  程序 测试一个锁条件的函数

  如果存在一把锁,它阻塞由参数说明的锁,则此函数返回持有这把现存锁的进程的ID,否则此函数返回0。通下面两个宏来调用此函数(它们也定义在ourhdr.h )。

#define is_read_lockable(fd,offset,whence,len)
lock_test(fd,F_RDLCK,offset,whence,len)
#define is_write_lockable(fd,offset,whence,len)
lock_test(fd,F_WRLCK,offset,whence,len)

阅读(899) | 评论(0) | 转发(0) |
0

上一篇:I/O多路转接全面透析

下一篇:临界资源

给主人留下些什么吧!~~