转载请注明出处:http://blog.csdn.net/cywosp/article/details/30083015

1. 场景概述
    在多线程开发中。相互排斥锁能够用于对临界资源的保护,防止数据的不一致。这是最为普遍的用法。那在多进程中怎样处理文件之间的同步呢?我们看看以下的图:
                                     

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3l3b3Nw/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

图中所看到的的是两个进程在无同步的情况下同一时候更新同一个文件的过程,其基本的操作是:
1. 从文件里读取序号。
2. 使用这个序号完毕应用程序定义的任务。

3. 递增这个序号并将其写回文件里。
从图中可得知两个进程读取分别添加了所读取到的序号,并写回到了文件里。可是假设有相互相互排斥的话,最后的值应该是1002,而不是所看到的的1001。

为了防止出现这样的情况,Linux提供了flock(对整个文件加锁)、fcntl(对整个文件区域加锁)两个函数来做进程间的文件同步。同一时候也可以使用信号量来完毕所需的同步。但通常使用文件锁会更好一些。由于内核可以自己主动将锁与文件关联起来。


2. flock()
    flock的声明例如以下
#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能够赋例如以下值:

               

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3l3b3Nw/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

    在默认情况下,假设还有一个进程已经持有了文件上的一个不兼容的锁。那么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操作),新的文件描写叙述符会引用同一个文件锁。

flock(fd, LOCK_EX);
new_fd = dup(fd);
flock(new_fd, LOCK_UN);
这段代码先在fd上设置一个相互排斥锁。然后通过fd创建一个指向同样文件的新文件描写叙述符new_fd。最后通过new_fd来解锁。

从而我们能够得知新的文件描写叙述符指向了同一个锁。所以,假设通过一个特定的文件描写叙述符获取了一个锁而且创建了该描写叙述符的一个或多个副本,那么,假设不显示的调用一个解锁操作,仅仅有当文件描写叙述符副本都被关闭了之后锁才会被释放。

    由上我们能够推出。假设使用fork()创建一个子进程。子进程会复制父进程中的全部描写叙述符。从而使得它们也会指向同一个文件锁。比如以下的代码会导致一个子进程删除一个父进程的锁:
flock (fd, LOCK_EX);
if (0 == fork ()) {
    flock (fd, LOCK_UN);
}
所以,有时候能够利用这些语义来将一个文件锁从父进程传输到子进程:在fork()之后,父进程关闭其文件描写叙述符。然后锁就仅仅在子进程的控制之下了。

通过fork()创建的锁在exec()中会得以保留(除非在文件描写叙述符上设置了close-on-exec标记而且该文件描写叙述符是最后一个引用底层的打开文件描写叙述的描写叙述符)。

    假设程序中使用open()来获取第二个引用同一个文件的描写叙述符,那么。flock()会将其视为不同的文件描写叙述符。例如以下代码会在第二个flock()上堵塞。
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, lockf, fcntl

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

  2. Linux文件锁flock

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

  3. linux文件锁flock【转】

    转自: https://www.cnblogs.com/kex1n/p/7100107.html linux文件锁flock   在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要 ...

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

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

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

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

  6. linux系统编程之文件与io(五)

    上一节中已经学习了文件描述符的复制,复制方法有三种,其中最后一种fcntl还并未使用到,关于这个函数,不光只有复制文件描述符的功能,还有其它一些用法,本节就对其进行一一剖析: fcntl常用操作: 这 ...

  7. Linux 文件锁

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

  8. Linux 系统编程

    简介和主要概念 Linux 系统编程最突出的特点是要求系统程序员对它们工作的的系统的硬件和操作系统有深入和全面的了解,当然它们还有库和系统调用上的区别. 系统编程分为:驱动编程.用户空间编程和网络编程 ...

  9. Linux系统编程【转】

    转自:https://blog.csdn.net/majiakun1/article/details/8558308 一.Linux系统编程概论 1.1 系统编程基石 syscall: libc:标准 ...

随机推荐

  1. 前端控件之Jquery datetimepicker的使用总结

    效果图 在介绍jquery datetimepicker的使用方法前,我们先来看一下它的实现效果图,这样以便让你更快地了解它是否是你所需要的. 下面我截了四张常用的效果图(截取自http://xdso ...

  2. 谨记给UpdatePanel中动态添加的控件赋ID

    原文:谨记给UpdatePanel中动态添加的控件赋ID 昨天下定决 心对上次做的布局编辑器控件加以改进,其中最主要变化的就是要完全使用ASP.NET AJAX!但是很遗憾,虽然耳闻已久,但目前对AS ...

  3. 让你提前认识软件开发(35):怎样改动SQL脚本以完毕需求?

    第2部分 数据库SQL语言 怎样改动SQL脚本以完毕需求? SQL脚本的改动和C语言代码的改动流程是一样的,都要遵循下面步骤:         第一步,阅读需求.弄清楚自己要完毕什么功能.       ...

  4. TCP/IP协议栈源码图解分析系列10:linux内核协议栈中对于socket相关API的实现

    题记:本系列文章的目的是抛开书本从Linux内核源代码的角度详细分析TCP/IP协议栈内核相关技术 轻松搞定TCP/IP协议栈,原创文章欢迎交流, byhankswang@gmail.com linu ...

  5. Audio Offload

    Audio Offload 音频分载,是系统将音频分载到声卡硬件进行分载处理的功能.从Windows 8开始,音频的硬件加速和分载处理又回来了.为什么说又回来了呢? 因为声卡自创通公司发明开始,相当长 ...

  6. css样式hover图片闪烁问题

    主要是ie8及ie8以下版本浏览器会出现此问题, 问题核心是因为hover选择器没有缓存即将要替换的图片, 所以导致替换期间有一个极其短暂的空白期. 解决方案: 采用 background-posit ...

  7. as 的妙用

    个人理解:as跟is is 相当于判断里的“==” 是与否 if(e.OriginalSource is Button) as 一般用来转换另一种object e.OriginalSource as ...

  8. 一类斜率优化的dp(特有性质:只能连续,不能交叉)

    hdu3480 给定一个有n个数的集合,将这个集合分成m个子集,要求子集的并等于全集求花费最小. 花费为该子集的(最大数-最小数)的平方. 我们将n个数排序, a < b < c < ...

  9. MyEclipse中“擅自乱改”项目名导致项目报错的处理

    最近几天培训的过程中,经常有同学手一抖,默默的修改了本来配置部署好的项目名,导致项目报错…… 遇到这种事情,我一般会做的处理就是重新新建项目,然后把包和各种文件ctrl+c ctrl+v,遇到项目小还 ...

  10. iOS国际化和genstrings所有子文件夹本地化字符串

    iOS国际化和genstrings所有子文件夹本地化字符串 在最近的一个繁忙的对外工程.每天加班.没有时间更新博客.简单谈一下知识的国际化. 首先,我们使用串.必须NSLocalizedString( ...