Unix记录锁使用总结

1.      原理说明

Unix系统中,记录锁的功能是:一个进程正在读或修改文件的某个部分时,可以阻止其他进程修改同一文件区。即其锁定的是文件的一个区域或整个文件。

记录锁有两种类型:共享读锁,独占写锁。基本规则是:多个进程在一个给定的字节上可以有一把共享的读锁,但在一个给定字节上的写锁只能有一个进程独用。即:如果在一个给定的字节上已经有一把读或多把读锁,则不能在该字节上再加写锁;如果在一个字节上已经有一把独占性的写锁,则不能再对它加任何读锁。

如下图所示:

注意加读锁时,读描述符必须是读打开,加写锁时,读描述符必须是写打开。

2.      记录锁的使用

2.1.      函数原型

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

    具体描述见附录。

2.2.      死锁

如果两个进程互相等待对方持有并且不释放的资源时,则这两个进程就处于死锁状态。如果记录锁锁定的是文件的不同区域,要十分小心这一点。另外在记录锁和其他具有阻塞功能的机制如基于TCPsocket通信一起使用时,也要注意,避免永久阻塞。

2.3.      锁继承与释放

1.当一个进程终止时,它所建立的锁全部释放。关闭一个文件描述符时,该进程通过这一描述符可以存放的文件上的任何一把锁都被释放。

2.fork产生的子程序不继承父进程的锁。

3.执行exec后,新程序可以继承原执行程序的锁。

2.4.      其它

如果在一个进程中对一个文件加锁后再加锁,会有什么结果呢?如下:

void func1()

{

    对文件加读锁

    。。。

    解读锁

}

 

 void func_tmp( )

{

    对文件加写锁;

    。。。

    func1( );

   。。。

   。。。

    解写锁

}

该错误比较容易犯,由于是同一个进程,第二次加锁时不会阻塞。所以又不容易发现。查看内核系统调用代码会发现,内核认为这种情况是调用者进行了锁的类型替换,于是唤醒其它阻塞在该锁的进程,这样就起不到我们所要的效果了。另外如果是写锁嵌套写锁,内核会在第一次解锁时就把锁释放,也达不到理想的效果。

3.      记录锁与文件锁的区别

记录锁:程序对某个文件拥有的所有锁都将在相应的文件描述符被关闭时自动清除。在程序结束时也会自动清除各种锁。

文件锁:在程序异常退出时,锁文件还存在。由于锁文件存在,会对其它进程使用该资源误认为被占用。

4.      附录

fcntl函数有5种功能:

1.复制一个现有的描述符(cmd=F_DUPFD.

2.获得/设置文件描述符标记(cmd=F_GETFDF_SETFD).

3.获得/设置文件状态标记(cmd=F_GETFLF_SETFL).

4.获得/设置异步I/O所有权(cmd=F_GETOWNF_SETOWN).

5.获得/设置记录锁(cmd=F_GETLK,F_SETLKF_SETLKW).

 

4.1.      cmd对应的命令

1. F_DUPFD     

返回一个如下描述的(文件)描述符:

a.最小的大于或等于arg的一个可用的描述符

b.与原始操作符一样的某对象的引用

c.如果对象是文件(file)的话,返回一个新的描述符,这个描述符与arg 共享相同的偏移量(offset)

d.相同的访问模式(,写或读/)

e.相同的文件状态标志(:两个文件描述符共享相同的状态标志)

f.与新的文件描述符结合在一起的close-on-exec 标志被设置成交叉式访问execve(2)的系统调用

2.F_GETFD     

取得与文件描述符fd联合close-on-exec标志,类似FD_CLOEXEC.如果返回值和FD_CLOEXEC进行与运算结果是0的话,文件保持交叉式访问exec(),否则如果通过exec运行的话,文件将被关闭(arg 被忽略)

3.F_SETFD     

设置close-on-exec 标志。该标志以参数argFD_CLOEXEC位决定。   

4.F_GETFL     

取得fd的文件状态标志,如同下面的描述一样(arg被忽略)

5.F_SETFL     

设置给arg描述符状态标志,可以更改的几个标志是: O_APPEND O_NONBLOCKO_SYNCO_ASYNC

6.F_GETOWN     

取得当前正在接收SIGIO或者SIGURG信号的进程id或进程组id,进程组id返回成负值(arg被忽略)

7.F_SETOWN    

设置将接收SIGIOSIGURG信号的进程id或进程组id,进程组id通过提供负值的arg来说明,否则arg将被认为是进程id

4.2.      F_GETFLF_SETFL命令字的标志

描述如下:

1.O_NONBLOCK   

非阻塞I/O;如果read(2)调用没有可读取的数据,或者如果write(2)操作将阻塞,readwrite调用返回-1EAGAIN错误

2.O_APPEND      

强制每次写(write)操作都添加在文件大的末尾,相当于open(2)O_APPEND标志

3.O_DIRECT      

最小化或去掉readingwriting的缓存影响.系统将企图避免缓存你的读或写的数据.如果不能够避免缓存,那么它将最小化已经被缓存了的数据造成的影响.如果这个标志用的不够好,将大大的降低性能

4.O_ASYNC        

I/O可用的时候,允许SIGIO信号发送到进程组,例如:当有数据可以读的时候

在修改文件描述符标志或文件状态标志时必须谨慎,先要取得现在的标志值,然后按照希望修改它,最后设置新标志值。不能只是执行F_SETFDF_SETFL命令,这样会关闭以前设置的标志位。

4.3.      记录锁

获得/设置记录锁的功能:(cmd=F_GETLK,F_SETLKF_SETLKW)

1.F_GETLK         

通过第三个参数arg(一个指向flock的结构体)取得第一个阻塞lock description指向的的锁.取得的信息将覆盖传到fcntl()flock结构的信息.如果没有发现能够阻止本次锁(flock)生成的锁,这 个结构将不被改变,除非锁的类型被设置成F_UNLCK.

2.F_SETLK         

按照指向结构体flock的指针的第三个参数arg所描述的锁的信息设置或者清除一个文件segment.F_SETLK被用来实现共享(或读) (F_RDLCK)或独占()(F_WRLCK),同样可以去掉这两种锁(F_UNLCK).如果共享锁或独占锁不能被设置,fcntl()将立即返 回EAGAIN.

3.F_SETLKW         

除了共享锁或独占锁被其他的锁阻塞这种情况外,这个命令和F_SETLK是一样的.如果共享锁或独占锁被其他的锁阻塞,进程将等待直到这个请求能够完成. fcntl()正在等待文件的某个区域的时候捕捉到一个信号,如果这个信号没有被指定SA_RESTART,fcntl将被中断.

 当一个共享锁被set到一个文件的某段的时候,其他的进程可以set共享锁到这个段或这个段的一部分.共享所阻止任何其他进程set独占锁到这段保护区域的任何部分.如果文件描述符没有以读的访问方式打开的话,共享锁的设置请求会失败

独占锁阻止任何其他的进程在这段保护区域任何位置设置共享锁或独占锁.如果文件描述符不是以写的访问方式打开的话,独占锁的请求会失败.

结构体flock的指针:

struct flcok

{

short int l_type; /* 锁定的状态*/
short int l_whence;/*
决定l_start位置
*/
off_t l_start; /*
锁定区域的开头位置
*/
off_t l_len; /*
锁定区域的大小
*/
pid_t l_pid; /*
锁定动作的进程
*/
};

l_type 有三种状态:

F_RDLCK 建立一个供读取用的锁定

F_WRLCK 建立一个供写入用的锁定
F_UNLCK
删除之前建立的锁定

l_whence 也有三种方式:

SEEK_SET 以文件开头为锁定的起始位置。

SEEK_CUR 以目前文件读写位置为锁定的起始位置

SEEK_END 以文件结尾为锁定的起始位置。

返回值      成功则返回0,若有错误则返回-1,错误原因存于errno.

4.4.      fctl的返回值

fcntl的返回值与命令有关。如果出错,所有命令都返回-1,如果成功则返回某个其他值。下列四个命令有特定返回值:

F_DUPFD——返回新的文件描述符

F_GETFD/F_GETFL——返回相应标志

F_GETOWN——返回一个正的进程ID或负的进程组ID

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值