转自: https://www.cnblogs.com/kex1n/p/7100107.html

linux文件锁flock

 

在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock。

flock,建议性锁,不具备强制性。一个进程使用flock将文件锁住,另一个进程可以直接操作正在被锁的文件,修改文件中的数据,原因在于flock只是用于检测文件是否被加锁,针对文件已经被加锁,另一个进程写入数据的情况,内核不会阻止这个进程的写入操作,也就是建议性锁的内核处理策略。

flock主要三种操作类型:
LOCK_SH,共享锁,多个进程可以使用同一把锁,常被用作读共享锁;
LOCK_EX,排他锁,同时只允许一个进程使用,常被用作写锁;
LOCK_UN,释放锁;

进程使用flock尝试锁文件时,如果文件已经被其他进程锁住,进程会被阻塞直到锁被释放掉,或者在调用flock的时候,采用LOCK_NB参数,在尝试锁住该文件的时候,发现已经被其他服务锁住,会返回错误,errno错误码为EWOULDBLOCK。即提供两种工作模式:阻塞与非阻塞类型。

服务会阻塞等待直到锁被释放:
flock(lockfd,LOCK_EX)
服务会返回错误发现文件已经被锁住时:
ret = flock(lockfd,LOCK_EX|LOCK_NB)
同时ret = -1, errno = EWOULDBLOCK

flock锁的释放非常具有特色,即可调用LOCK_UN参数来释放文件锁,也可以通过关闭fd的方式来释放文件锁(flock的第一个参数是fd),意味着flock会随着进程的关闭而被自动释放掉。

flock其中的一个使用场景为:检测进程是否已经存在;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int checkexit(char* pfile)
{
    if (pfile == NULL)
    {  
        return -1;
    }  
    int lockfd = open(pfile,O_RDWR);
    if (lockfd == -1)
    {  
        return -2;
    }  
    int iret = flock(lockfd,LOCK_EX|LOCK_NB);
    if (iret == -1)
    {  
        return -3;
    }  
 
    return 0;
}

  

1. 场景概述

在多线程开发中,互斥锁可以用于对临界资源的保护,防止数据的不一致,这是最为普遍的使用方法。那在多进程中如何处理文件之间的同步呢?我们看看下面的图:

图中所示的是两个进程在无同步的情况下同时更新同一个文件的过程,其主要的操作是:

  • 1. 从文件中读取序号。
  • 2. 使用这个序号完成应用程序定义的任务。
  • 3. 递增这个序号并将其写回文件中。

从图中可得知两个进程读取分别增加了所读取到的序号,并写回到了文件中,但是如果有相互互斥的话,最后的值应该是1002,而不是所示的1001。为了防止出现这种情况,Linux提供了flock(对整个文件加锁)、fcntl(对整个文件区域加锁)两个函数来做进程间的文件同步。同时也可以使用信号量来完成所需的同步,但通常使用文件锁会更好一些,因为内核能够自动将锁与文件关联起来。

2. flock()

flock的声明如下

 
 
1
2
3
4
#include <sys/file.h>
 
// Returns 0 on success, or -1 on error
int flock (intfd, int operation);

fcntl()函数提供了比该函数更为强大的功能,并且所拥有的功能也覆盖了flock()所拥有的功能,但是在某些应用中任然使用着flock()函数,并且在继承和锁释放方面的一些语义 中flock()与fcntl()还是有所不同的。

flock()系统调用是在整个文件中加锁,通过对传入的fd所指向的文件进行操作,然后在通过operation参数所设置的值来确定做什么样的操作。operation可以赋如下值:

在默认情况下,如果另一个进程已经持有了文件上的一个不兼容的锁,那么flock()会阻塞。如果需要防止这种情况的出现,可以在operation参数中对这些值取OR(|)。在这种情况下,如果一个进程已经持有了文件上的一个不兼容锁,那么flock()就会阻塞,相反,它会返回-1,并将errno设置成EWOULDBLOCK。

任意数量的进程可同时持有一个文件上的共享锁,但子任意时刻只能有一个进程能够持有一个文件上的互斥锁,(这有点类似读写锁)。下图是进程A先设置了锁,进程B后设置锁的支持情况:

无论程序以什么模式打开了文件(读、写或者读写),该文件上都可以放置一把共享锁或互斥锁。在实际操作过程中,参数operation可以指定对应的值将共享锁转换成互斥锁(反之亦然)。将一个共享锁转换成互斥锁,如果另一个进程要获取该文件的共享锁则会阻塞,除非operation参数指定了LOCK_NB标记,即:(LOCK_SH | LOCK_NB)。锁的转换过程不是一个原子操作,在转换的过程中首先会删除既有的锁,然后创建新锁。

3. 锁继承与释放的语义

flock()根据调用时operation参数传入LOCK_UN的值来释放一个文件锁。此外,锁会在相应的文件描述符被关闭之后自动释放。同时,当一个文件描述符被复制时(dup()、dup2()、或一个fcntl() F_DUPFD操作),新的文件描述符会引用同一个文件锁。

 
 
1
2
3
flock(fd, LOCK_EX);
new_fd = dup(fd);
flock(new_fd, LOCK_UN);

这段代码先在fd上设置一个互斥锁,然后通过fd创建一个指向相同文件的新文件描述符new_fd,最后通过new_fd来解锁。从而我们可以得知新的文件描述符指向了同一个锁。所以,如果通过一个特定的文件描述符获取了一个锁并且创建了该描述符的一个或多个副本,那么,如果不显示的调用一个解锁操作,只有当文件描述符副本都被关闭了之后锁才会被释放。

由上我们可以推出,如果使用fork()创建一个子进程,子进程会复制父进程中的所有描述符,从而使得它们也会指向同一个文件锁。例如下面的代码会导致一个子进程删除一个父进程的锁:

 
 
1
2
3
4
5
flock (fd, LOCK_EX);
 
if (0 == fork ()) {
    flock (fd, LOCK_UN);
}

所以,有时候可以利用这些语义来将一个文件锁从父进程传输到子进程:在fork()之后,父进程关闭其文件描述符,然后锁就只在子进程的控制之下了。通过fork()创建的锁在exec()中会得以保留(除非在文件描述符上设置了close-on-exec标记并且该文件描述符是最后一个引用底层的打开文件描述的描述符)。

如果程序中使用open()来获取第二个引用同一个文件的描述符,那么,flock()会将其视为不同的文件描述符。如下代码会在第二个flock()上阻塞。

 
 
1
2
3
4
5
fd1 = open ("test.txt", O_RDWD);
fd2 = open ("test.txt", O_RDWD);
 
flock (fd1, LOCK_EX);
flock (fd2, LOCK_EX);

4. flock()的限制

flock()放置的锁有如下限制

  • 只能对整个文件进行加锁。这种粗粒度的加锁会限制协作进程间的并发。假如存在多个进程,其中各个进程都想同时访问同一个文件的不同部分。
  • 通过flock()只能放置劝告式锁。
  • 很多NFS实现不识别flock()放置的锁。

注释:在默认情况下,文件锁是劝告式的,这表示一个进程可以简单地忽略另一个进程在文件上放置的锁。要使得劝告式加锁模型能够正常工作,所有访问文件的进程都必须要配合,即在执行文件IO之前先放置一把锁。

linux文件锁flock【转】的更多相关文章

  1. Linux文件锁flock

    Linux文件锁flock 在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock. flock,建议性锁 ...

  2. Linux文件锁flock ,检测进程是否已经存在

    在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock.  头文件:#include<sys/fil ...

  3. Linux 文件锁flock 实现两个进程相互监听存活状态

    表头文件  #include<sys/file.h> 定义函数  int flock(int fd,int operation); 函数说明  flock()会依参数operation所指 ...

  4. php原子操作,文件锁flock,数据库事务

    php原子操作,文件锁flock,数据库事务 php没有继承posix标准支持的unix锁,只封装了一个linux系统调用flock(信号量也能做成锁),按理也是可以使用锁机制的,虽然效率低一点.ph ...

  5. linux使用flock文件锁解决crontab冲突问题

    * * * * * flock -xn /dev/shm/redis.lock -c "/usr/local/bin/redis-server" 可以用flock命令,配合使用rs ...

  6. 每天进步一点点——Linux文件锁编程flock

    转载请注明出处:http://blog.csdn.net/cywosp/article/details/30083015 1. 场景概述     在多线程开发中.相互排斥锁能够用于对临界资源的保护,防 ...

  7. Linux文件锁学习-flock, lockf, fcntl

    参考  linux中fcntl().lockf.flock的区别 这三个函数的作用都是给文件加锁,那它们有什么区别呢? 首先flock和fcntl是系统调用,而lockf是库函数.lockf实际上是f ...

  8. linux使用flock文件锁

    使用linux flock 文件锁实现任务锁定,解决冲突 格式: flock [-sxun][-w #] fd# flock [-sxon][-w #] file [-c] command flock ...

  9. Linux 文件锁

    当多个进程同时访问操作同一个文件时,我们怎么保证文件数据的正确性. linux通常采用的方法是文件上锁,来避免共享资源的产生竞争状态. 文件锁包括建议性锁和强制性的锁: 建议性的锁 :顾名思义,相对温 ...

随机推荐

  1. Mac OS Terminal 几个快捷键

    在Mac系统中几个键位组合可以使Terminal的操作更加灵活方便. 1.将光标移动到行首:ctrl + a 2.将光标移动到行尾:ctrl + e 3.清除屏幕:            ctrl + ...

  2. touchstart,touchmove判断手机中滑屏方向

    滑动屏幕    touchstart:接触屏幕时触发,touchmove:活动过程触发,touchend:离开屏幕时触发 首先获取手接触屏幕时的坐标X,Y //获取接触屏幕时的X和Y$('body') ...

  3. Ibatis的环境搭建以及遇到的问题解决

    新建Java项目IbatisTest,加入Mysql和ibatis的驱动包; 在数据库中新建一张表student表,添加字段sid.sname.major.birth; 在java项目中添加bean对 ...

  4. AJAX-----07XMLHttpRequest对象的处理返回的JSON类型数据

    要玩json首先就需要知道一般都数据是怎么处理的: <!DOCTYPE html> <html lang="en"> <head> <me ...

  5. LocalDB简介和在VS2012及以上版本的使用

    http://www.cnblogs.com/fzrain/p/3812364.html?utm_source=tuicool LocalDB简介和在VS2012及以上版本的使用   之前一不小心把自 ...

  6. eclipse 怎么新建工作空间workspace

    打开eclipse 点击文件“File”菜单切换工作空间“Switch Workspace”>其它“Other” 点击“Browser”选择新的工作空间目录. 选择新的工作空间目录,点击确定. ...

  7. jquery Ajax中的dataType简析

    jquery中的ajax有好几种运用方式,但是基本上都是使用的$.ajax()方法,很多人经常会使用它来从后台获取json格式的数据,但是经常发现返回的json字符串并不能自动的转换成js里的json ...

  8. 简单修改 MySQL 的 root 账号密码

    首先这是一篇非常非常初级的教程. 平时为了方便,经常是直接在网上下载 PHP + MySQL 的集成环境,但有一些 MySQL 的 root 账号是没有密码的(例如大名鼎鼎的 XAMPP 就是这样), ...

  9. 开发设计模式(五)单例模式(Singleton Pattern)

    http://blog.sina.com.cn/s/blog_89d90b7c0101805m.html 单例模式:意思就是只有一个实例.单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提 ...

  10. Linux定时运行与开机运行任务

    http://os.51cto.com/art/200805/75144.htm at命令与crontab命令 http://os.51cto.com/art/201007/211874.htm ht ...