文档章节

Linux进程同步之记录锁(fcntl)

andrew810810
 andrew810810
发布于 2017/05/12 13:51
字数 1591
阅读 45
收藏 0

记录锁相当于线程同步中读写锁的一种扩展类型,可以用来对有亲缘或无亲缘关系的进程进行文件读与写的同步,通过fcntl函数来执行上锁操作。尽管读写锁也可以通过在共享内存区来进行进程的同步,但是fcntl记录上锁往往更容易使用,且效率更高。

记录锁的功能:当一个进程正在读或修改文件的某个部分是,它可以阻止其他进程修改同一文件区。对于这个功能阐述我认为有三点要解释的:

  • 记录锁不仅仅可以用来同步不同进程对同一文件的操作,还可以通过对同一文件加记录锁,来同步不同进程对某一共享资源的访问,如共享内存,I/O设备。
  • 对于劝告性上锁(POSIX定义的记录锁即是这种类型的锁),当一个进程通过上锁对文件进行操作时,它不能阻止另一个非协作进程对该文件的修改。
  • 即使是强制性上锁(有些系统定义),也不能完全保证该文件不会被另一个进程修改。因为强制性锁对unlink函数没有影响,所以一个进程可以先删除该文件,然后再将修改后的内容保存为同一文件来实现修改。具体可参考《APUE》P367 。

1记录锁函数接口

记录上锁的POSIX接口函数fcntl如下:

/* Do the file control operation described by CMD on FD. 
   The remaining arguments are interpreted depending on CMD. */  
int fcntl (int __fd, int __cmd, ...);  
  
//根据cmd的不同有以下三种类型的调用  
int fcntl(int fd, int cmd);  
int fcntl(int fd, int cmd, long arg);  
int fcntl(int fd, int cmd, struct flock *lock);  

由函数名称可知fcntl的功能是对文件的控制操作,根据传入不同的操作类型命令cmdfcntl会执行不同的操作,fcnt根据cmd不同,接收可变的参数。具体有以下五种类型的操作:

/* 
cmd = F_DUPFD,复制一个文件描述符; 
*/  
int fcntl(int fd, int cmd);  
  
/* 
cmd = F_GETFD,获得文件描述符标志; 
cmd = F_SETFD,设置文件描述符标志;arg = 描述符标志的值,目前只定义了一个标志: FD_CLOEXEC 
int fcntl(int fd, int cmd); 
int fcntl(int fd, int cmd, long arg); 
*/  
  
/* 
cmd = F_GETFL,获得文件状态标志; 
cmd = F_SETFL,设置文件状态标志;arg = 状态标志的值 
int fcntl(int fd, int cmd); 
int fcntl(int fd, int cmd, long arg); 
*/  
  
/* 
cmd = F_GETOWN,获得当前接收SIGIO和SIGURG信号的进程ID或进程组ID 
cmd = F_SETOWN,设置接收SIGIO和SIGURG信号的进程ID或进程组ID;arg = 进程ID或进程组ID 
int fcntl(int fd, int cmd); 
int fcntl(int fd, int cmd, long arg); 
*/  
  
/* 
Return value: 
 
对于成功的调用,根据操作类型cmd不同,有以下几种情况: 
       F_DUPFD  返回新的文件描述符 
       F_GETFD  返回文件描述符标志 
       F_GETFL  返回文件状态标志 
       F_GETOWN 进程ID或进程组ID 
       All other commands  返回0 
调用失败, 返回-1,并设置errno。 
*/  

上面四个功能都是fcntl提供的很常用的操作,关于记录锁的功能就是fcntl提供的第五个功能,具体使用如下:

int fcntl(int fd, int cmd, struct flock *lock);  
  
/* 
cmd = F_GETLK,测试能否建立一把锁 
cmd = F_SETLK,设置锁 
cmd = F_SETLKW, 阻塞设置一把锁 
 
*/  
//POSIX只定义fock结构中必须有以下的数据成员,具体实现可以增加  
struct flock {  
      short l_type;    /* 锁的类型: F_RDLCK, F_WRLCK, F_UNLCK */  
      short l_whence;  /* 加锁的起始位置:SEEK_SET, SEEK_CUR, SEEK_END */  
      off_t l_start;   /* 加锁的起始偏移,相对于l_whence */  
      off_t l_len;     /* 上锁的字节数,如果为0,表示从偏移处一直到文件的末尾*/  
      pid_t l_pid;     /* 已经占用锁的PID(只对F_GETLK 命令有效) */  
      /*...*/  
};  
//Return value: 前面已经说明;  

F_SETLK:获取(l_type为F_RDLCK或F_WRLCK)或释放由lock指向flock结构所描述的锁,如果无法获取锁时,该函数会立即返回一个EACCESS或EAGAIN错误,而不会阻塞。

F_SETLKW:F_SETLKW和F_SETLK的区别是,无法设置锁的时候,调用线程会阻塞到该锁能够授权位置。

F_GETLK:F_GETLK主要用来检测是否有某个已存在锁会妨碍将新锁授予调用进程,如果没有这样的锁,lock所指向的flock结构的l_type成员就会被置成F_UNLCK,否则已存在的锁的信息将会写入lock所指向的flock结构中

这里需要注意的是,用F_GETLK测试能否建立一把锁,然后接着用F_SETLK或F_SETLKW企图建立一把锁,由于这两者不是一个原子操作,所以不能保证两次fcntl之间不会有另外一个进程插入并建立一把相关的锁,从而使一开始的测试情况无效。所以一般不希望上锁时阻塞,会直接通过调用F_SETLK,并对返回结果进行测试,以判断是否成功建立所要求的锁。

2记录锁规则说明

前面我们说了记录锁相当于读写锁的一种扩展类型,记录锁和读写锁一样也有两种锁:共享读锁(F_RDLCK)和独占写锁(F_WRLCK)。在使用规则上和读写锁也基本一样:

  • 文件给定字节区间,多个进程可以有一把共享读锁,即允许多个进程以读模式访问该字节区;
  • 文件给定字节区间,只能有一个进程有一把独占写锁,即只允许有一个进程已写模式访问该字节区;
  • 文件给定字节区间,如果有一把或多把读锁,不能在该字节区再加写锁,同样,如果有一把写锁,不能再该字节区再加任何读写锁。

如下表所示:

需要说明的是:上面所阐述的规则只适用于不同进程提出的锁请求,并不适用于单个进程提出的多个锁请求。即如果一个进程对一个文件区间已经有了一把锁,后来该进程又试图在同一文件区间再加一把锁,那么新锁将会覆盖老锁。

 

 

参考:

http://blog.csdn.net/anonymalias/article/details/9197641

本文转载自:http://blog.csdn.net/anonymalias/article/details/9197641

上一篇: linux uname
andrew810810
粉丝 3
博文 141
码字总数 117648
作品 0
朝阳
私信 提问
fcntl 锁在 Go 中通过 execve 之后不生效的问题

fcntl 锁在 Go 中通过 execve 之后不生效的问题 背景 man 2 fcntl Record locks are not inherited by a child created via fork(2), but are preserved across an execve(2). 看到 fcntl 的......

辰林
2018/07/10
0
0
Linux系统文件I/O编程(二)---文件锁函数

文件锁 上一节:http://blog.csdn.net/mybelief321/article/details/8989755讲述的5个基本函数函数open()、read()、write()、lseek()和close()实现的文件的打开、读/写等操作,本节将讨论在文...

长平狐
2013/06/17
517
0
fcntl文件锁

在多任务操作系统环境中,如果一个进程尝试对正在被其他进程读取的文件进行写操作,可能会导致正在进行读操作的进程读取到一些被破坏或者不完整的数据;如果两个进程并发对同一个文件进行写操...

长平狐
2012/09/03
329
0
0-linux 环境编程修炼指南——外功心法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/q1007729991/article/details/52770103 学习交流群: Linux 环境编程 610441700 说明:本系列文章并不能取代 ...

--Allen--
2016/10/09
0
0
SylixOS文件记录锁使用

1. 文件记录锁介绍 文件锁锁定的是整个文件,而记录锁定还可以锁定文件的某一特定部分,即从文件的某一相对位置开始的一段连续的字节流。 当一个进程正在读取或者修改文件的某个部分时,使用...

张荣荣123
2017/04/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Jenkins系列_插件安装及报错处理

进入Jenkins之后我们可以进行插件的安装,插件管理位于以下模块: 发现上面报了一堆错误,是因为插件的依赖没有安装好,那么这一节,就先把这些错误解决掉吧。解决完成后,也就基本会使用插件...

shzwork
今天
2
0
mysql mysql的所有查询语句和聚合函数(整理一下,忘记了可以随时看看)

查询所有字段 select * from 表名; 查询自定字段 select 字段名 from 表名; 查询指定数据 select * from 表名 where 条件; 带关键字IN的查询 select * from 表名 where 条件 [not] in(元素...

edison_kwok
昨天
9
0
多线程同时加载缓存实现

import com.google.common.cache.Cache;import com.google.common.cache.CacheBuilder;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorServi......

暗中观察
昨天
3
0
利用VisualVM 内存查看

准备工作,建几个测试类。等下就是要查看这几个类里面的属性 package visualvm;public class MultiObject { private String str; private int i; MultiObject(String str...

冷基
昨天
2
0
组装一台工作游戏两用机

一、配置清单如下: 分类 项目 价格(元) 主板 华硕(ASUS)TUF Z370-PLUS GAMING II 电竞特工 Z370二代 支持9代CPU 1049 CPU 英特尔(Intel) i7 8700K 酷睿六核 盒装CPU处理器 2640 风扇 九...

mbzhong
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部